WordPress Hooks - Actions & Filters

ST

Seb Toombs

May 10 2021 ()

7 min read

WordPress is, without a doubt, one of the most ubiquitous content management systems (CMS) and website platforms there is. In fact it powers roughly 40% of all sites on the internet (at the time of writing). There is much debate about the utility, security, stability, speed & scalability of WordPress, often for the wrong reasons. Arguments aside, one of the most powerful features of WordPress is the hook system.

WordPress hooks are divided into two types; actions, and filters. Actions and filter hooks in WordPress are what has allowed WordPress to go from simply pretty basic PHP blogging platform, to a fully fledged, very extensible CMS.

The hook, action & filter system is how all plugins are able to add such incredible functionality, even changing the way parts of WordPress work.

Understanding how to use actions and filters will allow you to learn to build awesome plugins, modify other authors plugin & theme code, and generally become a WordPress Wizard!

For all it's power, the hook system in WordPress is actually pretty simple, and I'm going to try and answer all the questions around it I can such as;

  • How to add filters to WordPress
  • How to use filters in WordPress
  • How filters work
  • What are filters
  • Where to add filters & where to put filters
  • How actions work
  • What are actions in WordPress

Let's get started!

Actions & filters explained

Actions and filters are actually two types of the same thing, so for simplicity here I'm going to call them both hooks. Actions are a hook. Filters are a hook. (Fun fact: actions are actually filters! I'll get to that in a minute).

With that out of the way, here's the most basic explanation of what filters and actions (hooks) are;

Hooks, are functions (that you write) that are called by the WordPress core code, at various points in the execution.

To explain this more, let's take a step back. Imagine you're writing some code, and you'd like to let other people modify the output.

Take the following greeting function that accepts a name and returns a greeting for that name.

<?php

function greetingFunction($name) {

  $greeting = 'Hello';
  
  return $greeting . ' ' . $name;
  
}

greetingFunction('Seb');
// -> 'Hello Seb'

How could we go about this? Well, the way that WordPress accomplishes this is to store a global variable containing all the registered hooks, then call them at the appropriate time. Let's look at how we might do this ourselves;

<?php
// Set up a global variable to hold a 'callback'
// function to modify our greeting
$greetingHook = null;

function greetingFunction($name) {
  global $greetingHook;

  // Set up our greeting
  $greeting = 'Hello';
  
  // See if anyone has set $greetingHook callback
  if(is_callable($greetingHook)) {
    // Execute the callback, and overwrite our greeting
    // with the return value
    $greeting = $greetingHook();
  }
  
  return $greeting . ' ' . $name;
  
}

// Before calling 'greetingFunction', let's assign
// a callback
$greetingHook = function() {
  return "G'day";
}
// Now when we call greetingFunction
greetingFunction('Seb');
// -> 'G'day Seb'

A more comprehensive example might allow $greetingHook to be an array so that multiple callbacks can be registered (our above example only allows one callback, and any subsequent usages will overwrite the first one), and might also pass the initial value of $greeting into the callback.

For example;

<?php
// Set up a global variable to hold multiple callback
// functions to modify our greeting
$greetingHooks = [];

function greetingFunction($name) {
  global $greetingHooks;

  // Set up our greeting
  $greeting = 'Hello';
  
  // See if anyone has set any $greetingHooks callbacks
  foreach($greetingHooks as $greetingHook) {
    if(is_callable($greetingHook)) {
      // Execute the callback, and overwrite our greeting
      // with the return value
      $greeting = $greetingHook($greeting); // Pass the initial value
    }
  }
  
  return $greeting . ' ' . $name;
  
}

// Before calling 'greetingFunction', let's assign
// a couple of callbacks
$greetingHooks[] = function($greeting) {
  // $greeting right now should be 'Hello'
  // Let's overwrite it 
  return "G'day";
}
$greetingHooks[] = function($greeting) {
  // At this point, $greeting should be 'G'day'
  // Let's append something and return
  return $greeting . ' there';
  // Returns 'G'day there'
}

// Now when we call greetingFunction
greetingFunction('Seb');
// -> 'G'day there Seb'

Now we've created a system that allows the value for our greeting function to be modified or overwritten by possibly many other parts of the code.

This is how filters work! They pass the initial value into each registered callback in turn and then finally return the resulting value.

Of course, the WordPress filter system is a bit more complete than the example above. It offers a level of abstraction so that it can be used for many many instances without having to set up a global variable for each, and it offers the ability to remove, and set the order (priority) of callbacks.

Actions are filters. Remember that from earlier? Can you see from the two examples above what the difference between actions and filters is? The only difference is that filters care about the return value. Actions simply discard the return value - they don't care. Actions are good for situations where you need to trigger some side-effect (send an email, log something, display something) and filters are good for modifying some state/variable/context.

What is an action?

An action is a callback that is executed at a specified point to perform some sort of side-effect (such as send an email, log something, display some content).

What is a filter?

A filter is a callback that is executed at a specified point in order to modify some value, state, context or functionality. Examples might include changing the location of a redirect, changing the output of a function.

How to use WordPress filters & actions

With the lesson out of the way, let's examine how to actually use WordPress' hook system.

To use WordPress hooks (actions & filters), there are four WordPress functions you will need:

  • add_filter & add_action
  • apply_filters & do_action

These two pairs of functions are the two sides of the hook system: one adds a hook, the other executes the hook.

add_filter & add_action

These two functions are the main ones you're going to want to know if you're largely just looking to modify the functionality of WordPress, or other plugins etc. They work exactly the same, but one registers a filter, the other an action. (If you're not sure on the difference, check the section above).

How to use add_filter & add_action

<?php
//
// add_filter( $hookName, $callback, $priority, $numArgs );
//

// To add a filter to our greeting_function example
add_filter('greeting_function', function($greeting) {
  return 'Hello';
}, 10, 1);

// In this example, the hookName is 'greeting_function'
// The callback accepts 1 argument (the greeting) and returns a value
// The priority is 10. Hooks are executed in order: 0 comes first, then 1, 2, 3, 4
// Multiple hooks can have the same priority
// The last argument (1) says we expect 1 argument


//
// add_action( $hookName, $callback, $priority, $numArgs );
//
add_action('greeting_function', function($greeting) {
  error_log('The greeting was: ' . $greeting);
}, 10, 1);

// In this example, the hookName is still 'greeting_function'
// The callback still accepts 1 argument (the greeting)
// But we don't return anything and instead do some side-effect (error_log)
// The priority is 10 again
// And we still expect 1 parameter

How to use apply_filters and do_action

<?php
//
// apply_filters( $hookName, $arg1, $arg2 ... )
//

// To use any registered filter hooks, we can call apply_filters
// Apply filters expects the hookName, and any arguments

$greeting = apply_filters('greeting_function', $greeting);

// The number of arguments passed in here
// Dictates the number that add_filter should request as the last parameter


// 
// do_action( $hookName, $arg1, $arg2 ... )
//

do_action('greeting_function', $greeting);

Filter & action hook example

Take the example from earlier of our greetingFunction. Let's modify this to use a filter instead. We'll also add a function to print the greeting and add an action to that.

<?php

function greetingFunction($name) {

  $greeting = 'Hello';
  
  // Allow users to override the greeting
  $greeting = apply_filters('greeting_function', $greeting);
  
  return $greeting . ' ' . $name;
  
}

function printGreeting($name) {
  // Allow users to run actions before / after the greeting
  do_action('before_print_greeting');
  echo greetingFunction($name);
  do_action('after_print_greeting');
}

add_filter('greeting_function', function($greeting) {
  // Return "G'day" instead of "Hello";
  return "G'day";
});

add_action('before_print_greeting', function() {
  echo '<p>';
})

add_action('after_print_greeting', function() {
  echo '</p>';
});

printGreeting('Seb');
// -> '<p class="greeting">G'day Seb</p>'

Where to add filters / where to put filters

Now that you've got an idea of how filters work, and what filters are, a pretty common question is: "where to add filters?". Which is totally fair!

We know we shouldn't modify the WordPress core code. We know we shouldn't modify other author's plugins or themes. So where to put filters? (And actions).

Well there are two options.

1. functions.php

If you're working on a theme that you can edit (your own custom theme, a child theme etc), the easiest place is to put them in functions.php.

It's often not super important where you put them, just try and keep your code logical, readable, and maintainable.

2. a custom plugin

Custom plugins are actually very easy to write! Obviously the scope can be huge, and a plugin can be many hundreds (or thousands!) of files. But that needn't be the case. A custom plugin can be as simple as one php file in the wp-content/plugins directory.

3. A helpful plugin...

Ok when I said there were two options, I lied. There are quite a number of options, but the above two are probably what you're searching for. There's a third option I often reach for:

Code Snippets on the WordPress repository

Code snippets is a really useful plugin I often use to add arbitrary actions and filters to websites. This is often useful if I don't have edit access to the theme and don't want to create a custom plugin.

(Note: I am in no way affiliated with Code Snippets, and receive nothing in return for mentioning it)

WordPress hooks, actions, filters summary

Hopefully that's enough to give you a jump-start understanding hooks in WordPress, and you're well on your way to becoming a WordPress wizard.

Pro-tip: Here's a quick pro-tip for how I figure out how to use undocumented filters and actions in other author's plugins in order to modify some functionality.

  • Download the plugin to your local machine
  • Find some relatively unique thing (maybe it's a frontend classname or piece of markup, maybe it's a shortcode etc) and search the whole source
  • If you find that what you're looking for was called from a function, keep 'pulling the thread' until you find an action, hook, filter where you can jump in
  • This might not always be possible, depending on the quality of the plugin, but 8 times out of 10 you'll get there
  • This works really well with implementing custom features in Woocommerce!

As always, if you have questions, more tips, feedback etc, reach out on Twitter!