Demystifying the WordPress Hook System
If you’ve been developing websites with WordPress (including plugin and theme development) chances are you’ve heard these terms: Hooks
, Actions
, and Filters
. These are part of the Event-driven Architecture Pattern, which WordPress uses.
Are you new to WordPress development or finding it difficult to understand the basic concepts? I can’t recommend highly enough Simon Codrington’s Introduction to WordPress Plugin Development tutorial. He did a great job of explaining Actions
, and Filters
.
In this tutorial, I’ll be demystifying the WordPress hook system, leaving no stone unturned. Without further ado, let’s get started.
Hooks, Actions, Filters. What Are They?
‘Hooks’ are basically events triggered by WordPress core, themes and plugins at various stages of their execution or interpretation by PHP. When these events are triggered, all the functions and/or class methods hooked or attached to them are executed in their correct order.
Hooks come in two forms, Actions and Filters. While the former is used to add and remove features or functionality at various stages of process execution, the latter modifies the behavior of various features and implementations. Don’t worry if you still don’t understand. You will when we start seeing some code examples below.
Importance of the Hook System in WordPress
The importance of the hook system in WordPress is simply extensibility. It makes it possible to add and remove features, as well as tweak/modify the implementation of features in WordPress core, plugins and themes.
When you write extensible plugins and themes, you make it possible for other developers to improve and extend them without ever editing the core source code.
Allow me to cite an example. Unlike most payment gateways, my 2Checkout Payment Gateway for WooCommerce plugin does not include an icon displaying the supported credit card types on the checkout page because I felt it is unnecessary. But you know what; I added a filter
in case a user feels otherwise.
It just so happened that we received a support request from a customer requesting for the inclusion of the icon. We were able to provide a code snippet to the customer that hooks into the filter and includes the icon.
Delving into the WordPress Hook System
At various stages of WordPress execution, a large number of events are triggered commonly using the do_actions()
and apply_filters()
PHP functions. These events can be subscribed or hooked to via add_action()
and add_filter()
.
Please note the use of the word ‘commonly’. There are other ways events can be triggered. We’ll explore that in the second part of this tutorial.
Below is an example of an action
in a plugin. This action is fired after a successful user registration in my ProfilePress user registration plugin.
/**
* Fires after a user registration is completed.
*
* @param int $form_id ID of the registration form.
* @param mixed $user_data array of registered user info.
* @param int $user_id ID of the registered user.
*/
do_action( 'pp_after_registration', $form_id, $user_data, $user_id );
During WordPress execution, all the functions hooked into this action will be processed.
An example of a filter hook is the_content
in WordPress core which filters every posts contents.
/**
* Filter the post content.
*
* @since 0.71
*
* @param string $content Content of the current post.
*/
$content = apply_filters( 'the_content', $content );
Take Note
In do_action()
, the first argument is the name of the action hook and subsequent arguments are variables available to functions that hook into the action.
And in apply_filters()
, the first argument is the name of the filter hook, the second is the data or value on which the functions hooked to the filter are modified or applied. Subsequent arguments are variables/values available to functions that hook into the filter.
Don’t worry, all this will make more sense as we examine code examples.
Action Hook Examples
Example #1
Taking my ProfilePress plugin’s pp_after_registration
action for a spin; let’s say we want to implement a feature where users will receive an SMS (via an assumed messaging service called Dolio) welcoming them to your website immediately after registration. Our function hook could be in this form:
add_action( 'pp_after_registration', 'send_users_welcome_sms', 20, 3 );
function send_users_welcome_sms( $form_id, $user_data, $user_id ) {
global $service_locator;
$username = $user_data['username'];
$firstName = $user_data['first_name'];
$lastName = $user_data['last_name'];
$phoneNumber = $user_data['phone_number'];
$text = <<<SMS_CONTENT
Hello $firstName $lastName, Welcome to SitePoint. "\r\n"
User ID: $user_id "\r\n"
Username: $username "\r\n"
Password: The password you sign up with "\r\n"
SMS_CONTENT;
$dolio = $service_locator->get( 'dolio_sdk' );
$dolio->phone_number( $phoneNumber );
$dolio->sms_content( $text );
$dolio->send();
}
The third argument of add_action
in the code above is the hook priority which specifies the order in which the function hooked to pp_after_registration
action will be executed. Leaving this empty will default to 10
. While the fourth argument specifies the number of arguments the function hook will accept. Default to 1
if empty.
Assuming I left out the fourth argument, thus defaulting to 1
, the $user_data
and $user_id
variable will be null
because we only told the function to accept just one argument.
Example #2
WordPress includes the following action
hooks — wp_head
and wp_footer
— that are both triggered in the head tag and before the closing body tag on the front end respectively.
These hooks can be used to display script and data at those strategic locations.
Let’s check out some code examples.
The code below uses wp_head
to include Google’s site verification meta tag to the header of the WordPress front end.
add_action( 'wp_head', 'google_site_verification' );
function google_site_verification() {
echo '<meta name="google-site-verification" content="ytl89rlFsAzH7dWLs_U2mdlivbrr_jgV4Gq7wClHDUJ8" />';
}
All hook functions will be anonymous in lieu of the named function to avoid unnecessary repetition of function’s names. For example, the code for Google site verification Meta tag above will now become:
add_action( 'wp_head', function () {
echo '<meta name="google-site-verification" content="ytl89rlFsAzH7dWLs_U2mdlivbrr_jgV4Gq7wClHDUJ8" />';
});
The code below uses wp_footer
to add JavaScript in the footer area of WordPress front end.
add_action( 'wp_footer', function () {
echo '<script type="text/javascript" src="http://example.com/wp-content/plugins/site-specific-plugin/hello-bar.js"></script>';
});
Enough of the action hooks code example, let’s check out filters.
Filter Hook Examples
Example #1
Say we are developing an ad inserter
plugin that will programmatically insert ads before and after every post content, the the_content
filter is what we need.
The code below includes the text ‘We love SitePoint’ before and after every post content.
add_filter( 'the_content',
function ( $content ) {
$text = sprintf( '<div class="notice alert">%s</div>', __( 'We love SitePoint', 'sp' ) );
$content = $text . $content . $text;
return $content;
});
Code explanation: the content of $text
variable is the same as <div class="notice alert">We love SitePoint</div>
albeit internationalized so that it can be localized. Confused? Please take a look at my tutorials on WordPress i18n and l10n.
Mind you, the function parameter $content
, is the variable that supplies the post content.
We then append the custom text before and after the post content, save the resultant data to $content
and subsequently return it.
Note: all filter
hook functions must return the variable parameter after manipulation or modification.
Example #2
Another filter example we’ll look at is the_title
. Below is how it is defined in line 158 of wp-includes/post-template.php
.
/**
* Filter the post title.
*
* @since 0.71
*
* @param string $title The post title.
* @param int $id The post ID.
*/
return apply_filters( 'the_title', $title, $id );
The code below modifies only the title of a post with ID 5978 by appending - WeLoveSitePoint
to it. This is possible thanks to the $id
argument.
add_filter( 'the_title', function ( $title, $id ) {
if ( $id == '5978' ) {
$title .= ' - WeLoveSitePoint';
}
return $title;
}, 10, 2
);
Conclusion
The reason WordPress continues to be the leading content management system is because of its extensibility.
The WordPress Hook system has made it possible for WordPress to be transformed into powerful web applications, whether that be an ecommerce store with WooCommerce, a forum with bbPress or even a social networking site with BuddyPress.
In Part 2 of this tutorial, I will sharing some cool and little known facts about the hook system in WordPress such as how to: use them in a class, hook static and non-static methods to actions and filters, use namespaces, its caveats and solutions and a whole lot more. So stay tuned and happy coding.