A guide for non-developers: WordPress Actions, Filters, and Hooks

A WordPress page is made up of a whole load of functions and database queries, with WordPress and the theme working together to output text, images, stylesheets, and other files. The browser interprets all of these and puts them all together into one web page. Throughout its code, WordPress has included “hooks”, so that people can “hang” their own code on those hooks. A lot of the Customizr theme is written in PHP, using them. There are two types of hooks: actions and filters.

  • Actions allow you to add extra functionality at a specific point in the processing of the page—for example, you might want to add extra widgets or menus, or add a promotional message to your page.
  • Filters allow you to intercept and modify data as it is processed—for example, you might want to insert another CSS class in a WordPress HTML element, or modify some of your pages blocks.

In brief: actions do stuff; filters change stuff.

Getting down to details

When Gill comes by, tell her to go to the store to get some paint. When Jack comes by bragging about how great he is, get him to say that Gill is better.

Wait, what? I thought this was an article about actions, filters and hooks? Instead, we’re talking about arrogant home-improvers? Well yes. These are ways of understanding what’s going on when you use actions and filters.Let’s look at actions and filters in turn.

Actions:

When Gill comes by, tell her to go to the store to get some paint.

We can do this by hooking onto an action hook. That is, we can use the add_action function (written add_action()) to add functionality—do stuff—at a particular point.Sending Gill to the store to get paint might look like this in PHP:

// Send Gill to get paint
add_action( 'after_gill_arrives' , 'send_gill_to_get_paint', 10 , 2 );
function send_gill_to_get_paint( $gill_has_keys, $gill_has_car ) {
  // If $gill_has_keys and $gill_has_car are both true
  if ( $gill_has_keys && $gill_has_car ) {
    echo 'Gill, please go to the store and get some paint. Thank you!';
  }
}

What did we just do there?

  • We watched for a particular thing to happen—Gill having arrived; in programming terms the ‘after_gill_arrives’ hook;
  • When it happened, we did something—we sent her to the store to get paint; in programming terms we added an action to call the send_gill_to_get_paint() function, which prints a message on the page;
  • We used the $gill_has_keys and $gill_has_car arguments to perform some basic logic;
  • We set other information:
    • The priority of this action: Whether it will run before, or after, other functions attached to the same hook. In this case we set the priority to 10, the default. If we want another function to run before this, we would give the other function a lower value (which means it will be executed first).
    • How many arguments (variables) that the function accepts. These arguments are passed from the action hook to our function. In this case, we set this value to 2.

How did it work?

In simple terms, add_action() tells WordPress to do something when it arrives at the specified do_action() hook.But we can only use our add_action() in the example above if we know that the ‘after_gill_arrives’ action hook exists in our theme/plugin. Our theme/plugin needs to have something like this in it:do_action( ‘after_gill_arrives’ , $gill_has_keys = true , $gill_has_car = true );This tells WordPress to create a hook called ‘after_gill_arrives’, run any actions that are attached to this hook, and pass the arguments $gill_has_keys and $gill_has_car to those actions (the 2 arguments we specified above).

A simple add_action() example

Now let’s look at a simple example using the Customizr theme. Let’s add some text after the header:

// Add some text after the header
add_action( '__after_header' , 'add_promotional_text' );
function add_promotional_text() {
  // If we're not on the home page, do nothing
  if ( !is_front_page() )
    return;
  // Echo the html
  echo "<div>Special offer! June only: Free chocolate for everyone!</div>";
}

Inside the Customizr core code, as the very last action in header.php, Customizr has:

do_action ( '__after_header' )

This is where our add_action() is hooking itself.You can also use remove_action() to remove actions from their hooks. For example,  this snippet removes the slider from one place—using remove_action() to unhook it from where it’s currently hooked—and adds it somewhere else.And how do we add the remove_action() to the page’s code? Yes, that’s right: with an add_action(). In the case of snippet for moving the slider, we hook our function in the <head> section at the very top of the page, to make sure it’s executed after all the actions are loaded, but before the rest of the page is built. Take a look at that slider snippet to see if it makes more sense to you now.

Filters:

When Jack comes by, bragging about how he’s the best, tone down his boasting.

We can change Jack’s boasting comments by hooking onto a filter. That is, we can use add_filter() to modify functionality—change stuff—at a particular point.Toning down his boasting might look like this in PHP:

// Cut Jack's boasting
add_filter( 'jacks_boast' , 'cut_the_boasting');
function cut_the_boasting($boast) {
  // Replace "best" with "second-best"
  $boast = str_replace ( "best" , "second-best" , $boast );
  // Append another phrase at the end of his boast
  $boast = $boast . ' However, Gill can outshine me any day.';
  return $boast;
}<br>

What did we just do there?

  • We looked for a particular thing that we wanted to change—Jack’s boast that he’s the best; in programming terms the ‘jacks_boast’ filter;
  • When we found it, we changed it—we changed “best” to “second-best” and we added another phrase on the end; in programming terms, we filtered the output by calling the cut_the_boasting() function, which replaced part of the string and appended another string (the “.” character concatenates two PHP strings);
  • We used the $boast argument (in this case a string that says something like “I’m the best!”) as the basis for our changes.
  • We returned a string at the end of the function. This is very important. If you don’t return a string in a filter, you might disrupt the functioning of a program (in this case, we would simply silence Jack … which may not be a bad thing).

How did it work?

In simple terms, add_filter() tells WordPress to swap its data with ours when it arrives at the ‘jacks_boast’ filter hook. Neat!But we can only use our add_filter() filter in the example above if we know that the ‘jacks_boast’ filter hook exists in our theme/plugin. (If the hook doesn’t exist, our function will simply never be called.) Behind the scenes, the theme/plugin has to have something like this in it:

echo apply_filters('jacks_boast', "I'm the best in the world.");

This tells WordPress to create a hook called ‘jacks_boast’, apply any filters that are attached to this hook, and pass those filters the string “I’m the best in the world.”. If there are no filters attached to the hook, then the apply_filters() function will simply return the string “I’m the best in the world.”: effectively a default.

A simple add_filter() example

Now let’s look at an easy example in the Customizr theme. Let’s change the url of the link in the logo:

// Change url that is linked from logo
add_filter( 'tc_logo_link_url', 'change_site_main_link' );
function change_site_main_link() {
  return 'http://example.com';
}<br>

Inside the Customizr core code, in the function that displays the logo (in class-header-header_main.php), Customizr has:

apply_filters( ‘tc_logo_link_url’, esc_url( home_url( ‘/’ ) ) )

This is where our add_filter() is hooking itself. The esc_url() function eliminates invalid characters etc. in urls and the home_url() function retrieves the home url for the site. So without any filtering, the ‘tc_logo_link_url’ filter returns the home page’s address.In this example, we didn’t even take any notice of the incoming arguments (the home url), because we knew we were just going to completely overwrite it.Remember: When you use a filter, you must always return something.