🤯 50% Off! 700+ courses, assessments, and books

Alternative Ways of Triggering Events in WordPress

Collins Agbonghama
Share

In the first part of this series on the WordPress hook system, we learned about the WordPress hook system and the two types of hooks actions and filters alongside some code examples of how they work.

In this second part of this series, we’ll be learning about alternative ways of triggering events in WordPress and how to hook static and non-static class methods to actions and filters.

WordPress Hooks

In the previous article, I made the following statement:

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().

Take note of my use of the word “commonly”. There are other ways events can be triggered. We’ll explore that in the second part of this tutorial.

The other ways events can be triggered are via do_action_ref_array() function for action hooks and apply_filters_ref_array() for filter hooks.

Both do_action(), do_action_ref_array() and apply_filters(), apply_filters_ref_array() are the same in that each pair are used to execute functions hooked to specific action and filter respectively. The difference is in how they specify their argument.

Unlike do_action() and apply_filters(), do_action_ref_array() and apply_filters_ref_array() specifies their argument as an array.

Let’s see some code examples to better understand how they work.

Code Examples

The action user_profile_update_errors is fired in WordPress before user profile update errors are returned and the profile is updated.

Say you added a custom field to the WordPress user profile and wanted to validate its input before WordPress saves the data to the database. This is the hook you need.

Here is how it is defined in WordPress core.

    /**
     * Fires before user profile update errors are returned.
     *
     * @since 2.8.0
     *
     * @param WP_Error &$errors WP_Error object, passed by reference.
     * @param bool     $update  Whether this is a user update.
     * @param WP_User  &$user   WP_User object, passed by reference.
     */
    do_action_ref_array( 'user_profile_update_errors', array( &$errors, $update, &$user ) );

The code below ensures a custom profile field named city (where users can enter their cities) is not left empty. If it is, an error to that effect will be displayed.

add_action( 'user_profile_update_errors', function ( $errors, $update, $user ) {
        if ( empty( $_POST['city'] ) ) {
            $errors->add( 'city_empty', __( 'City field cannot be left empty.' ) );
        }
    }, 10, 3 );

Let’s see a code example of apply_filters_ref_array().

The code below hooks into the bp_activity_permalink_redirect_url filter in bbPress to modify the intended redirect URL to http://website.com/custom-page/ before the redirect occurs for a single activity item.

add_filter( 'bp_activity_permalink_redirect_url', function ( $redirect, $activity ) {
        $redirect = 'http://website.com/custom-page/';

        return $redirect;

    }, 10, 2 );

When to Use do_action_ref_array() and apply_filters_ref_array()

In making your plugin or theme extensible by other developers, do_action_ref_array() and apply_filters_ref_array() are preferable to do_action() and apply_filters() when there are many additional variables or values to be passed to functions that hook into an action and filter are many.

Take for instance, you’re developing a user registration plugin, and you defined an action to fire after registration is complete with the registered user’s username, email address, first name, last name, address, city, state and country available to functions that hook to it. Here is how the code might look when you use do_action()

do_action('after_user_registration_completed', $username, $email, $firstname, $lastname, $address, $city, $state, $country);

Notice how the list of arguments makes the line of code long and ugly. Now compare the above with that of do_action_ref_array() below.

do_action_ref_array(
    'after_user_registration_completed',
    array(
        $username,
        $email,
        $firstname,
        $lastname,
        $address,
        $city,
        $state,
        $country
    )
);

Hooking Class Methods to Actions and Filters

The code examples we’ve been examining are about hooking named and anonymous functions to action and filter hooks.

So let’s see how to call or include hooks via add_action() and add_filter() within a class for processing during WordPress execution and also how class methods (static and non-static) can be hooked to actions and filters.

Most WordPress developers include all add_action() and add_filter() function calls in their class constructor which is then executed on instantiation like so:

class DemoPlugin {
    public function __construct() {
        add_action( 'wp_head', array( $this, 'google_site_verification' ) );

        add_filter( 'the_content', array( $this, 'we_love_sitepoint' ) );
    }


    /**
     * Include Google site verification meta tag to WordPress header.
     */
    public function google_site_verification() {
        echo '<meta name="google-site-verification" content="ytl89rlFsAzH7dWLs_U2mdlivbrr_jgV4Gq7wClHDUJ8" />';
    }


    /**
     * Append and prepend the text "We love SitePoint" to every post content.
     *
     * @param string $content
     *
     * @return string
     */
    public function we_love_sitepoint( $content ) {
        $text    = sprintf( '<div class="notice alert">%s</div>', __( 'We love SitePoint', 'sp' ) );
        $content = $text . $content . $text;

        return $content;
    }
}


new DemoPlugin();

From the code snippet above, you will discover that there is a difference in the way a function and class method is hooked to an action or filter in that, for a class method, the second argument of add_action() and add_filter() is an array of $this (a reference to the current object) and the method name.

For a static method, the class name is used instead of $this.

class DemoPlugin {
    public function __construct() {
        add_action( 'wp_head', array( 'DemoPlugin', 'google_site_verification' ) );
    }


    /**
     * Include Google site verification meta tag to WordPress header.
     */
    public static function google_site_verification() {
        echo '<meta name="google-site-verification" content="ytl89rlFsAzH7dWLs_U2mdlivbrr_jgV4Gq7wClHDUJ8" />';
    }
}

new DemoPlugin();

The above approach of including the class name for every static method you want to hook to a filter or action violates the don’t repeat yourself (DRY) principle and thus will make refactoring hard.

Instead, use the constant __CLASS__ which returns the class name it was declared in.

class DemoPlugin {
    public function __construct() {
        add_action( 'wp_head', array( __CLASS__, 'google_site_verification' ) );
    }

    // ...
}

new DemoPlugin();

Although I strongly discourage this, here is another way of including a static method to a hook.

class DemoPlugin {
    public function __construct() {
        add_action( 'wp_head', 'DemoPlugin::google_site_verification' );
    }

    // ...
}

new DemoPlugin();

Rather than include all add_action() and add_filter() function calls in a class constructor, I have seen some developers create a static class method which when called, initializes/executes the static methods hooked to an action or filter.

class DemoPlugin {
    public static function init() {
        add_action( 'wp_head', array( __CLASS__, 'google_site_verification' ) );
        add_filter( 'the_content', array( __CLASS__, 'we_love_sitepoint' ) );
    }

    // ...
}


DemoPlugin::init();

In this approach, all methods to be hooked to actions and filters must be static because $this is not accessible in static context.

Summary

In this second part of our series on WordPress hooks, we learned an alternative way of triggering action and filter events, when to use them, and finally, how to hook static and non-static class methods to actions and filters.

In the concluding part, we’ll examine how to hook methods of an instantiated class (object) to an action and filter, how to integrate a namespaced class method to a hook and the caveats of using namespaces in the WordPress hook system.

Happy coding!