It is well-known that WordPress is one of the most popular Content Management Systems available for building and maintaining a website. While a big part of that success is due to the ease-of-use, another big part of that is the wide variety of themes and plugins that are available to make WordPress do just about anything you can think of. What gives plugins and themes their true power is the Plugin API, which is a set of Actions and Filters, collectively known as Hooks, that are embedded within the core WordPress codebase. The goal of this post is to demystify the WordPress Hooks and enable you to start diving in and using them.

An Example — LEGO®

Most people have at least heard of, if not directly experienced, LEGO® toy bricks. With these toys, you can follow instructions in a set and build your own toys to play with. You can also creatively build something entirely new using your own imagination. Or you can combine the two approaches and customize a pre-designed set with your own modifications. All of this is made possible by the way that individual LEGO® pieces fit together: the bumps on the top and the gaps on the bottom, as well as a few other types of connections.

In our analogy, the bumps and gaps in the LEGO® bricks work the same way as Hooks in WordPress. You can add new functionality, remove default functionality, or just modify the current piece of data. Getting a firm understanding of this process will help you start to unlock the real power of WordPress.

Types of Hooks

There are two types of Hooks in WordPress: Actions and Filters. They work almost the same way, but it’s important to understand how they are different. Actions intend for you to simply do something, while filters intend for you to change something. Also, actions may provide variables to your code to give you more context, while filters will always provide at least one variable: the data you’re modifying.

Actions

Actions are used to insert your own code into a specific point of the WordPress core execution. Actions in WordPress look like this:

/** * Print scripts or data in the head tag on the front end. * * @since 1.5.0 */ do_action( 'wp_head' );

The function do_action() is used to trigger an action. In the example above, “wp_head” is the name of the action. If you want to hook into this action, you’ll need to know the name of the action so that WordPress runs your code in the correct place.

Filters

Just like actions, filters are used to insert your own code into a specific point of the WordPress core execution. What makes them different from actions is that filters always provide data to your code, and they always expect your code to provide data back again. Filters in WordPress typically look like this:

/** * Filter the list of CSS body classes for the current post or page. * * @since 2.8.0 * * @param array $classes An array of body classes. * @param string $class A comma-separated list of additional classes added to the body. */ $classes = apply_filters( 'body_class', $classes, $class );

The function apply_filters() is used to trigger a filter. In the example above, “body_class” is the name of the filter, and there are two variables passed in for context: $classes and $class . The result of the filter is assigned to the $classes variable. This is essentially how the filter works: A piece of data is passed through the filter and the filtered version is used by WordPress. In this case, the piece of data is the variable $classes .

Using Hooks

Adding your own functionality to the WordPress hooks is very straightforward. You’ll need the add_action() function for actions, and the add_filter() function for filters. Let’s get into some practical examples using the two hooks we mentioned before: “wp_head” and “body_class”. In each of the cases below, we’ll give a code example, and then explain what’s happening in that example.

Actions

/** * Add our own output to the HTML <head> element. */ function jpry_wp_head_action() { echo '<!-- This comment will show up inside the HTML <head> element! -->'; } add_action( 'wp_head', 'jpry_wp_head_action', 10, 0 );

In the code above, you can see that we’re calling the add_action() function with four parameters. The parameters are:

'wp_head' — This is the name of the hook that we want to tie into. 'jpry_wp_head_action' — This is the name of our function that WordPress should execute. In my example, you can see that it corresponds to a function name. 10 — This is the priority level of our function. 0 — This is the number of arguments (parameters) that our function ( jpry_wp_head_action() ) expects to receive.

In this example, I’m simply adding an HTML comment to the <head> block. When you view the source of the site, you will be able to see this comment within the <head> block after the code is added.

While I’ve included all of the available parameters in this example, it’s important to note that the last two parameters are optional. You should only include them if you want to override the default value that WordPress uses. I will explain this in more detail in the Optional Parameters section below.

Filters

/** * Add the "jpry" class to the HTML <body> element. * * @param array $classes The array of body classes. * @return array The modified array of classes. */ function jpry_body_class_filter( $classes ) { $classes[] = 'jpry'; return $classes; } add_filter( 'body_class', 'jpry_body_class_filter', 10, 1 );

Just like the add_action() function, we call the add_filter() function with 4 parameters:

'body_class' — This is the name of the hook that we want to tie into. 'jpry_body_class_filter' — This is the name of our function that WordPress should execute. Just like above, it corresponds to the function name that I created just above it. 10 — The priority level. 1 — The number of arguments that our function ( jpry_body_class_filter() ) expects to receive.

As I mentioned before about filters, they always expect to pass you data, and they always expect you to return data when you’re done. In the above example, you can see that my function jpry_body_class_filter() accepts a single parameter, named $classes . I know from looking at the documentation of this filter that $classes is an array of class names. I’m adding my own class and so I simply append my own data to the existing array. In order for this to work, it’s absolutely crucial to return the $classes variable back to the filter.

Not returning data back to a filter is a common cause of obscure bugs and support requests. Without the return statement, not only will your filter not add your data, but it will also cause the existing data to be empty! If you’re using a filter and you don’t seem to be getting any data back when you’re done, or if you’re seeing some strange bug somewhere that is hard to figure out, double-check to make sure you’ve included that return statement.

Optional Parameters

I previously mentioned that there are two optional parameters with each of these functions: priority and number of arguments.

The priority parameter does exactly what it says: it prioritizes your function with everything else that has been added to that same hook. WordPress executes functions in lowest-to-highest priority. When multiple functions have been added at the same priority level, then they are executed in the order that they were added.

The number of arguments parameter ensures that your function receives the correct number of parameters when it is called. This is relevant when you’re using an action or filter that passes more than one value. If we look at the body_class filter definition above, we can see that there are two pieces of data available to us: $classes and $class . While we don’t need both pieces of data for our specific use, there may be other developers who do need the extra data. In order to have the second variable passed to their function so that they can use it, they would set the number of arguments to 2 instead of 1 .

Resources

Hooks are an integral part of how WordPress functions, and so there are plenty of resources available to help you utilize them:

Do you have any questions or comments? Did you find an error, or think I missed something? Leave a comment below!