Wednesday, April 27, 2016

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.

WordPress Hooks

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.


Source: Demystifying the WordPress Hook System

No comments:

Post a Comment