Action and filter hooks are a fundamental part of the various WordPress APIs. Without them you're limited as to what you can do in your themes and (especially) your plugins.
But sometimes it can be easy to confuse the two, especially in the cases when WordPress has both an action hook and a filter hook with the same name.
In this article I'll define action and filter hooks and describe the difference between them, and I'll demonstrate how to use them in your themes and plugins. I'll also give some examples of when you might use each.
When you're adding action and filter hooks to your code (or you're hooking functions to them), it helps to understand how actions and filters are called by WordPress and what happens in what order. I won't cover that in detail here as we have another tutorial that does that job.
Definitions and Differences
Let's start with some definitions. I'll define action and filter hooks and functions too, so you can see the difference between them all.
Functions
Functions are the first thing most people work with when they're learning WordPress development; if you've added code to your theme's functions.php
file, then you'll have written a function.
Functions specify how something will happen. You code a function to query data, to output content, or to perform many other tasks. You can call (execute) functions directly in your theme's template files, or you can hook them to action or filter hooks. Functions can also include template tags such as conditional tags, to specify when the function should apply.
I'll show you the different ways to execute functions later in this article.
Action Hooks
Action hooks (or actions) are triggered when something takes place, such as loading a page, a user logging in, or a custom action that you define in your theme or plugin.
You can add your own action hooks using the do_action()
function, which I'll demonstrate shortly. Any functions you hook to that action will then run at that point in the code.
Filter Hooks
Filter hooks, or filters, control how something happens or change something that's already being output. You could use a filter to output metadata in a specific format, to override text output by your plugin, or to prevent something from being displayed at all.
You add filters in your code using the apply_filters()
function, which I'll demonstrate shortly. As the word 'apply' indicates, you apply filters to existing code, whereas an action you create using do_action()
is empty until you hook functions to it.
Using Functions, Actions, and Filters
Let's take a look at some examples demonstrating how you use each of functions, actions, and filters. First, we'll look at using functions directly in your code without attaching them to a hook.
Calling Functions Directly
Here's an example of a function that's called directly in a template file. In my client sites I add a colophon in the footer, which includes copyright information. Here's the function:
if ( ! function_exists( 'compass_colophon' ) ) { function compass_colophon() { ?> <section class="colophon" role="contentinfo"> <small class="copyright left"> <?php echo compass_copyright(); ?> <a href="<?php echo home_url( '/' ) ?>" title="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>" rel="home"> <?php bloginfo( 'name' ); ?> </a> </small><!-- #copyright --> <small class="credits right"> Powered by <a href="http://wordpress.org/">WordPress</a> and designed by <a href="http://compass-design.co.uk">Compass Design</a>. </a> </small><!-- #credits --> </section><!--#colophon--> <?php } }
This function is pluggable as I use it in a parent theme; if I then create a new function with the same name in my child theme, that will override this function. Note that the function includes another function, compass_colophon()
, calling it directly in the code.
This function is in the functions.php
file of my parent theme. I can call it directly in the footer.php
file of my theme, like so:
compass_colophon();
This outputs the code in the function at the point in my theme where I call it. You can also pass parameters to your functions, which are then used inside the function.
As I'll demonstrate shortly, this function could also be hooked to an action or a filter.
Hooking Functions to Actions
Rather than calling that colophon function directly, I'll have more flexibility if I attach it to a hook.
Creating Action Hooks
Instead of calling the compass_colophon()
function in my footer file, I can add an action hook at that point in the footer.php
file, by adding this:
do_action( 'compass_in_footer' );
The do_action()
function has one mandatory parameter, which is the name of the action. You can also optionally add arguments to it.
Hooking Functions to Actions
So now instead of calling my colophon function, I need to hook it to my new action hook. In my functions.php
file, I add this with my function:
add_action( 'compass_in_footer', 'compass_colophon' );
This hooks my function to the compass_in_footer
action, which means that the code inside my function will run at the point in the code where the action has been placed. The first parameter is the name of the action hook, and the second is the name of my function.
An advantage of doing it this way is that you can hook more than one function to the same action, and you can set the priority so they fire in the order you want them to.
So let's say I have another function I want to hook to my compass_in_footer
hook, called compass_smallprint()
, which contains some more small print:
if ( ! function_exists( compass_smallprint() ) ) { function compass_smallprint() { // contents of function here } } add_action( 'compass_in_footer', 'compass_smallprint', 20 );
You can see here that I've added a third parameter to my add_action()
function, which is the priority. The default priority is 10
, which will be applied if you leave this blank. So because I haven't set a priority for my compass_colophon()
function, setting 20 for the compass_smallprint()
function will make that function run after the compass_colophon()
function.
Unhooking Functions From Actions
Sometimes you want to stop a function from running, and you can't override it because it's not pluggable. If the function has been hooked to an action hook, then you can do this using the remove_action()
function.
So if I want to prevent my compass_smallprint()
function from running, I unhook it from the compass_in_footer
action like so:
remove_action( 'compass_in_footer', 'compass_smallprint', 20 );
The remove_action()
function has three parameters: the name of the action hook, the name of the function, and the priority with which the function was originally hooked to the action. You must include the priority for this to work.
You can also unhook all of the functions from an action if you want to prevent them all from executing. Be careful when doing this, as there may be functions you're not aware of hooked to your action.
To do this, use the remove_all_actions()
function:
remove_all_actions( 'compass_in_footer' );
Adding a priority number as the second parameter only removes the functions which are hooked to that action hook with the priority you've specified, which gives you more control.
Hooking Functions to Filters
You also have the option of hooking your functions to filter hooks. You do this when you want to alter or override some existing code. When you create the filter hook (using the apply_filters()
function), you wrap that around code in your theme or plugin, which is then altered by any filters attached to the hook.
This can be useful if you have theme or plugin options that you want to override a default setting, or if you're creating a parent theme that may have elements overridden by a child theme.
Creating Filter Hooks
The apply_filters()
function has three parameters: the name of the filter hook, the value which you want to filter (i.e. the default value), and optional variables which you then pass to the functions hooked to the filter.
You can add a filter in your theme template files or inside a function that is hooked via an action hook. Let's take a look at both options.
Returning to my compass_colophon()
function, I convert this to a filter by adding its contents to my footer.php
file inside the apply_filters()
function like so:
echo apply_filters( 'compass_colophon', ' <section class="colophon" role="contentinfo"> <small class="copyright left"> <?php echo compass_copyright(); ?> <a href="<?php echo home_url( '/' ) ?>" title="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>" rel="home"> <?php bloginfo( 'name' ); ?> </a> </small><!-- #copyright --> <small class="credits right"> Powered by <a href="http://wordpress.org/">WordPress</a> and designed by <a href="http://compass-design.co.uk">Compass Design</a>. </a> </small><!-- #credits --> </section><!--#colophon-->' );
This outputs the code that I've set as the second parameter of my apply_filters()
function.
However, I prefer not to add this directly to my theme template file, so I'll add the filter to the function that I'm already attaching via an action hook.
So I add the compass_in_footer
action to my footer.php
file using the do_action()
function as demonstrated above, and then I create a function in my functions.php
file which is hooked to that action and contains a filter:
if ( ! function_exists( 'compass_colophon' ) ) { function compass_colophon() { echo apply_filters( 'compass_colophon_filter', ' <section class="colophon" role="contentinfo"> <small class="copyright left"> <?php echo compass_copyright(); ?> <a href="<?php echo home_url( '/' ) ?>" title="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>" rel="home"> <?php bloginfo( 'name' ); ?> </a> </small><!-- #copyright --> <small class="credits right"> Powered by <a href="http://wordpress.org/">WordPress</a> and designed by <a href="http://compass-design.co.uk">Compass Design</a>. </a> </small><!-- #credits --> </section><!--#colophon-->' ); } add_action( 'compass_in_footer', 'compass_colophon' );
This means that I can now override the default content in one of three ways:
- by creating a new function called
compass_colophon()
in my child theme, which overrides the function in my parent theme as that's pluggable - by unhooking the
compass_colophon()
function from thecompass_in_footer
action hook and writing a new function which I attach to it in its place - by creating a new function which I then hook to the
compass_colophon_filter
filter hook, which overrides the value in myapply_filters()
function
In real life you wouldn't need to have this many options, so it's more likely that you'd apply filters to part of the content in your function rather than the whole thing.
So I could create two filters, one for the copyright section and another for the credits:
if ( ! function_exists( 'compass_colophon' ) ) { function compass_colophon() { echo '<section class="colophon" role="contentinfo">'; echo apply_filters( 'compass_copyright_filter', ' <small class="copyright left"> <?php echo compass_copyright(); ?> <a href="<?php echo home_url( '/' ) ?>" title="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>" rel="home"> <?php bloginfo( 'name' ); ?> </a> </small><!-- #copyright -->' ); echo apply_filters( 'compass_copyright_filter', ' <small class="credits right"> Powered by <a href="http://wordpress.org/">WordPress</a> and designed by <a href="http://compass-design.co.uk">Compass Design</a>. </a> </small><!-- #credits -->' ); echo '</section><!--#colophon-->'; } add_action( 'compass_in_footer', 'compass_colophon' );
Then I could either override the whole of my compass_colophon function by unhooking it or writing a new one in my child theme, or I could create a function hooked to the compass_copyright_filter
or compass_credits_filter
filter hook, to override each element individually.
Hooking Functions to Filters
To hook a function to a filter hook, you use the add_filter()
function, which has two parameters: the name of the hook and the name of the function.
So to change the credits, I would write this function:
function new_credits() { ?> <small class="credits right"> Powered by <a href="http://wordpress.org/">WordPress</a> and designed by <a href="http://rachelmccollin.co.uk">Rachel McCollin</a>. </a> </small><!-- #credits --> <?php } add_filter( 'compass_credits_filter', 'new_credits' );
This overrides the value set in my original compass_credits_filter
filter hook with the content of my new_credits()
function, but keeps everything else in the compass_colophon()
function the same.
You can also specify priorities when hooking functions to filters, in exactly the same way as with action hooks. Functions with a lower priority will be run first.
Unhooking Functions From Filters
As with action hooks, you can also remove functions from filter hooks. You do this using the remove_filter() function, which has three parameters: the name of the filter hook, the name of the function, and the priority, which is mandatory if a priority was set when the function was originally hooked to the filter.
So to remove my new_credits()
function, I use this:
remove_filter( 'compass_credits_filter', 'new_credits' );
The code output would then revert to the value I specified in my original apply_filters()
function. So if I wanted to remove the new_credits()
function and have nothing appear in its place, I'd have to add a new function. I then unhook the first function and hook my new function like so:
function no_credits() { return; } remove_filter( 'compass_credits_filter', 'new_credits' ); add_filter( 'compass_credits_filter', 'no_credits' );
Summary
Understanding the difference between action and filter hooks and being able to use both of them effectively will give your theme and plugin development a boost. In fact, without using hooks of at least one type, you can't write plugins at all, as the only way the code in your plugins is activated is via the action and filter hooks it's attached to.
This guide showed you how to add the same functionality using a function, an action hook and one or more filter hooks, along with techniques for removing functions from hooks and advice on when each technique is more useful.
As well as hooking functions to your own action and filter hooks that you create, you can hook them to the actions and filters provided by WordPress, such as the wp_head
action or the body_class
filter.
Comments