How to Use WordPress Action Hooks in Theme Customization

WordPress child themes give a relatively easy way to customize the look and feel of a theme. If the theme’s options don’t provide you with adequate design choices, you can just add a new rule to the child theme’s default stylesheet file called style.css. But what happens when you also want to modify the theme’s functionality? That is one of the cases when WordPress actions come to your help.

WordPress has become so popular partly because of its high customizability. The WordPress Core is loaded with different hooks that enable developers to modify or enhance the default functionality. Moreover, we are allowed to include custom hooks in our themes and plugins to help other developers to easily adjust our code to their needs.

About WordPress Hooks

WordPress hooks work somewhat similar to real-life hooks in the sense that you can catch the fish you want at the right spot if you properly use them.

You can remove a caught function (e.g. you can remove the WordPress admin bar for low-level users), you can leave it intact and enhance it with your own functionality (e.g. you can add more menus or widget areas to a theme), or you can override it (e.g. you can modify the behaviour of a core function).

There are two different kind of hooks in WordPress: actions and filters. In this post we will take a look at how we can make use of action hooks in theme customization.

How WordPress Hooks Work

To use a very simple language, actions indicate that something has happened during the WordPress page lifecycle: certain parts of the site have been loaded, certain options or settings have been set up, plugins or widgets have been initialized, and so on.

Filters are different from actions in their nature. They are used to pass data through, and modify, manage or intercept it before rendering it to the screen or saving user data into the database.

At every significant landmark of the WordPress page lifecycle there is either an action or a filter hook to which we can add our custom code to modify the default behaviour to our needs.

The certain actions and filters running during a request depend on which page was requested by the user agent: for example in a single post request hooks related to single posts are available, but hooks related to other parts of the site (e.g. the admin area) aren’t.

Find Action Hooks

The Action Reference of the WordPress Codex gives a detailed overview of the actions running through different requests. The important thing is that if we want to accomplish a task we need to hook into the right place, not before or after it, otherwise the action won’t be completed.

So for example if we want to add our Google Analytics code to a site we need to hook our action right before the footer is loaded.

If we speak about theme customization, action hooks can come from two different places: from WordPress Core and the theme itself. There are themes that don’t have hooks at all, but others provide developers with some or many – it’s always the theme author’s choice. The default Twenty Fifteen Theme has only one action hook for footer customization under the name of ‘twentyfifteen_credits’.

If you like to browse source code, you can also find action hooks easily. Action hooks are added to the code with the do_action() WordPress function.

If you run a quick search for the expression ‘do_action’ in a more advanced code editor – like I did in Eclipse below – you can see a list about the spots where you can hook your custom functionality into the core. I searched in the /wp-includes/ folder, but you can also run a search for the /wp-admin/ folder that contains the action hooks related to the WordPress dashboard (admin area).

The good thing is that the names of the action hooks are usually pretty self-explanatory, but there is usually a nice comment inside the code that can give you more knowledge whether the given action hook is good for the reason you want to use it for.

For example the code comment before the ‘widgets_init’ action hook says that it “fires after all default WordPress widgets have been registered”. If you take a peek at the code before this action hook, you can find all the default WP widgets’ initialization before it – so you can be sure that the comment didn’t lie, and if you want to register your own custom widget, this will be the right spot.

In many cases the source code provides us with much more information than the Codex, so it can be a good idea to learn how to quickly navigate in it.

Add Your Own Actions

When you want to add your own action, you need to create a custom function and bind this function to a specific action hook by using the add_action() WordPress function. Custom actions added with the add_action() function are usually triggered on the spot when the core calls the appropriate do_action() function.

Let’s see a simple example.

How To Find The Action Hook You Need

Let’s say you want to add your custom favicon to your site. First, you need to find the right action hook you can bind your own functionality to.

Let’s think. If you wanted to add a favicon to a plain HTML page where would you put it? Of course, you need to place it inside the <head> section of the HTML file with the following markup:

<link rel="shortcut icon" href="/" type="image/x-icon" />

So the action hook you need must be related to the loading of the <head> section.

(1) Open the Action Reference, and see what it has to offer. We are lucky, as if we browse through the actions, we can only find one, wp_head, that based on its name has the possiblity to be related to the loading of the <head> section.

(2) To be sure, let’s check the documentation in the WordPress Codex. The Codex advises that “you use this hook by having your function echo output to the browser”, so right now it seems to be perfect for us. But let’s check it in the source code.

(3) As this hook is not related to the admin area we will need to run our search in the /wp-includes/ folder. If we search for the word ‘wp-head’ we will get many results as this specific action is used by WP Core many times.

We need to look for the spot where it gets defined, so search for the expression do_action( ‘wp_head’. Note that we didn’t finish the parentheses, as we can’t be sure yet if this action has parameters or not.

Eclipse returns only one result that can be found inside the /wp-includes/general-template.php file. The comment before the action hook definition says that it “prints scripts or data in the head tag on front end”, so now we can be dead-sure that wp_head is the action hook we need.

Checking For Parameters

When you add your own actions you also need to be sure if the hook you want to use takes parameters or not. You can easily find this out by looking at the do_action() function.

The syntax of the do_action() function is the following:

do_action( 'name_of_action'[, $parameter1, $parameter2, ...] )

Only the name of the action is required, the parameters are optional. If you find arguments in the relevant call of the do_action() function, you need to include them in the declaration of the custom function you create.

If you don’t find any, then your custom function must work without arguments. In the do_action() definition of the wp_head action hook, there are no parameters.

Let’s compare it to an action hook that takes a parameter. The action hook called ‘wp_register_sidebar_widget’ takes one parameter that you always have to pass to the custom function you bind to the hook.

Let’s see the difference in the do_action() syntax of the two cases:

do_action( 'wp_head' );
do_action( 'wp_register_sidebar_widget', $widget );

In the first case there’s no parameter, so the custom function will use the following syntax:

function my_function_without_parameters() { ... }

In the second case there is one parameter that you always have to pass as an argument into the declaration of your custom function:

function my_function_with_parameters( $widget ) { ... }

How To Hook Your Custom Function In

Now we know everything we need. Let’s create our custom function that will display a favicon on our site.

First, create a new function without any arguments, then bind it to the wp_head action hook with the help of the add_action() WordPress function.

function custom_add_favicon() {
echo '<link rel="shortcut icon" href="/" type="image/x-icon" />';
add_action( 'wp_head', 'custom_add_favicon');

You need to pass the name of the action hook to the add_action() function as an argument first, then you need to add the name of your custom function.

These are the two required parameters of add_action(). It has two optional parameters too, priority and accepted arguments. Let’s see how to use these.

Define Priorities

It happens in many cases that there are more than one action bound to the same hook. So which one will be executed first? This is where we can use the $priority optional parameter of the add_action() function.

We add the priority as a positive integer, the default value being 10. If we want an action to be executed early, we give it a lower value, if we want it to be executed later, we give it a higher value.

So if we think that the favicon needs to be there early, we can enhance our previous add_action() call in the following way:

add_action( 'wp_head', 'custom_add_favicon', 5);

Please note that the priorities always have to be set relatively to the other custom functions that use the same action hook.

Add The Number of Accepted Arguments

You are required to add the number of accepted arguments in case you use an action hook that takes parameters. Let’s see the example we used before.

The action hook ‘wp_register_sidebar_widget’ takes one parameter, so when we bind our custom function to this hook, we also need to include this as an argument when we call the add_action() function.

Our code in this case will look like this:

function my_sidebar_widget_function( $widget ) {
// Your code
add_action( 'wp_register_sidebar_widget', 'my_sidebar_widget_function', 10, 1);

Note that we must also add the priority (we chose the default 10 here) to make sure that WordPress knows what each parameter means. If we omitted the priority, WordPress could suppose that 1 is the priority which is not true, as it indicates the number of the accepted arguments.


You can make many experiments with action hooks in theme customization. For example you can add your custom scripts (JS) and styles (CSS) with the wp_enqueue_scripts action hook, or your Google Analytics code with the wp_footer action hook.

You not only can add your own actions, but you can also remove complete functionalities from the WordPress core with the use of the remove_action() function that uses the same logic as add_action().

If you are a theme author, and you want to make an extensible theme, it can be a good idea to add your own custom action hooks to the appropriate template files with the do_action() function.

If you want to do so, think carefully about parameters that other developers who will use your theme will have to pass as arguments when they want to hook in their custom functionalities.

While designing the locations of your theme’s custom action hooks don’t forget that it does not make much sense to include custom theme hooks on the same spots where the WordPress Core itself has its own hooks.

A Quick (and in-Depth) Guide to WordPress Hooks

WordPress hooks are the thing to learn if you want to get into WordPress development. Hooks allows you to do two things: change default functionality within WordPress and add your own functionality without modifying core WordPress files at all.

Making sure you never modify core files is extremely important, but modifying and adding stuff seems impossible without it.

In this post, I’m going to show you how you can do it pretty easily with two types of hooks: actions and filters. You’ll need a basic understanding of HTML and PHP for this one, but not too much. Let’s dig in!

The Need for Hooks

Hooks are built into WordPress and are used to modify or add functionality to the core system. Let’s assume for a moment that WordPress does not provide any hooks. And let’s also say you work with a lot of scheduled posts and you would like to email yourself when a post is published. How would you go about doing that?

Without hooks you would need to modify core files. You would hunt down the code that is responsible for publishing a post and just after the function that performs the action, you would paste your own code.

This is detrimental for a number of reasons. The two big ones are updates and uncontrollable code. If you modify core WordPress files your code will work just fine but will be erased when you update WordPress to the next version. You would have to remember or track all of your changes and then put them back in. Not exactly convenient. Alternatively, you could simply not update WordPress, but that would be a huge security risk in the long run.

Even if you do manage to keep track of changes and update WordPress, you are left with a non-standard environment with uncontrollable code. Other WordPress developers will have a hard time dealing with your code, and the community as a whole will not be happy.

Enter Hooks

A hook does almost exactly what we talked about before (find the place where a post is published, paste your code), but replaces the horrible pasting bit with a placeholder. By default, there is a placeholder after the post publishing function, which allows you to tie functionality there. Here’s a shortened version of the actual wp_publish_post(), which you can find in wp-includes/post.php.

function wp_publish_post( $post ) {
  // Stuff that actually published the post  
  do_action( 'wp_insert_post', $post->ID, $post, true );

That do_action() bit basically says: You can tie your own function to me, they will all be executed. So whenever WordPress publishes a post using the wp_publish_post() function it goes through all the necessary steps to make it happen. It then moves on to the do_action() function. It’s first parameter is wp_insert_post. Any function which is tied to this wp_insert_post action will get executed.

Let’s look at an example.

To create a hooked function you need to create a simple plugin, use your theme’s functions.php file, or create a child theme and use the functions.php file in there. Let’s create a quick plugin now.

Create a new folder in the Plugins directory and name it “hook-example.” Create a “hook-example.php” file within that directory and paste the following code into it:

 * Plugin Name: Hook Test
 * Description: A simple plugin to test hooks

Your plugin is now ready. Head on over to the Plugins section in WordPress admin and activate it. Now let’s create a hooked function. In the hook-example.php file, paste the following:

add_action( 'wp_insert_post', 'email_post_author', 10, 3 );
function email_post_author( $post_id, $post, $update ) {
  $email = '';
  $subject = 'New Post Published';
  $message = 'A new post was published, use this link to view it: ' . get_permalink( $post->ID );
  wp_mail( $email, $subject, $message );

We’re using the add_action() function to let WordPress know that we’d like to hook a function into wp_insert_post. The second and third parameters are the priority and the arguments. We’ll get into that soon.

In our hooked function we simply define what we’d like to do. In this case send an email to ourselves. Whenever WordPress published a post it will look for all functions hooked into wp_insert_post and run them all.

So what have we achieved here? We’ve added functionality to a core part of WordPress without actually modifying the core files. All we needed was one extra line of code. This is very important! All you need to do is write a function that does what you need, then you hook it into a specific part of WordPress.

Actions and Filters

So far we’ve seen what an action is – it’s a piece of code that is executed at a specific time. A filter can be used to modify content before WordPress uses it. You could use a filter to modify the “your password is incorrect” text on the login page. Let’s take a look at wp-login.php:

if ( ! empty( $errors ) ) {
	 * Filter the error messages displayed above the login form.
	 * @since 2.1.0
	 * @param string $errors Login error message.
	echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";

The snippet from the actual file that handles logins shows that login error messages are displayed using an apply_filters() function. This is very similar in logic to the do-action() function.

My second parameter contains some sort of data. If you use a hooked function based on my first parameter you can modify this data, otherwise I’m going to use it as is. By default, if you enter a correct username but incorrect password you see the following notice:

If you think this is a bit unsafe because it exposes the fact that the username is correct you can hook a function to login_errors to modify it. Here’s how:

add_filter( 'login_errors', 'modify_login_errors' );
function modify_login_errors() {
    return 'Login unsuccessful, try again';

By implementing this change you’ve added a bit more security to your login process and you can also control the text.

Hooks, Actions, Filters, Hooked Function and Tags

There is some confusion about these terms above because sometimes they are used interchangeably. I myself mis-speak sometimes, so let’s get things straight just in case I mess up further down!

Hook is an umbrella term for actions and filters. Actions allow you to add your own functionality next to existing functionality. Filters allow you to modify existing functionality. Sometimes the word tag is used to refer to the string that indicates where you are adding your hook. A hooked function is a function you create that adds or modifies functionality.

The Anatomy of a Hook

When we use hooks we generally rely on two functions: add_action() and add_filter(). Both these function take four parameters:

  1. The first parameter is the tag. This is the bit that tells WordPress where to hook your function, when it should be executed.
  2. The second parameter should be the name of the hooked function.
  3. The third parameter is the priority of the hook. This determines the order in which it is executed if multiple functions are hooked into the same tag.
  4. The fourth parameter defines the number of parameters passed to this function. By default this is 1, but some tags (like the previous wp_insert_post) can have more.


The first parameter of both functions is a simple string that states when the hooked function is executed. There are many, many tags you can use. There are action tags that run when posts are deleted, categories are created, a user is logged in and more. Filter tags are run on messages for custom taxonomies, post title displays, dates and more. The Hooks Reference is a good place to start, but sometimes a Google search can be more effective!

Note that some tags may be referred to as variable hooks. There is a hook named “{old_status}_to_{new_status}” for example. This hook simply means there are a number of hooks defined for combinations. publish_to_trash would run when a publish post is trashed, future_to_draft would run when a scheduled post is set to draft status.

Hooked Function

Again, a simple string, which should be the exact name of the function. Since this will be a function name it should contain letters, numbers and underscores only.

Take extra care to make this function unique. If you name a function “send_email” it may clash with someone else’s function of the same name. It is common practice to prefix function names, something like: my_send_email, or wpmudev_send_email.

I also advise making your function names readable. You could name your function sae(), short for “send author email” but this is extremely bad practice as no one else will know what this means, and you will probably forget in a few months as well.

Hook Priority

The third function defines the priority of a hook. The lower the priority the sooner the function gets executed. In some cases the order is not important but in some cases it is essential. If you want to send a post publication email to yourself and the author, the order doesn’t much matter. You can use the default of 10 for both:

add_action( 'wp_insert_post', 'send_author_email', 10, 3 );
add_action( 'wp_insert_post', 'send_admin_email', 10, 3 );

However, if you would like to update some statistics whenever a post is updated and then notify the author the order suddenly becomes important:

add_action( 'save_post', 'send_admin_email', 10, 3 );
add_action( 'save_post', 'update_post_stats', 5, 3 );

As you can see, the order in which the add_action() calls are places is not important. The second call has a lower priority, therefore it will be executed first.

For filters you need to be more careful. Since filters modify data they may overwrite each other. If two filters are hooked into the same tag, the one with the lower priority is executed first. Then, the one with the higher priority is executed which may change the data completely. Many times this is desirable behavior, it’s just something to be aware of.


The fourth parameter sets the number of parameters passed to our hooked function. This is something you will need to hunt down as it depends on what is in the source code.

If you go back to see how we changed the login errors you’ll notice the following function: apply_filters( 'login_errors', $errors ). The first parameter is the tag, the rest are arguments. There is only one here, so one argument is passed to our hooked function.

In case of wp_insert_post() you can see the following in the core files: do_action( 'wp_insert_post', $post->ID, $post, true );. The first parameter is the tag, the rest are arguments, so the value here is 3.

Our Own Hooks

The great thing about the hooks system is that we can create our own. All we need is the two familiar functions we’ve seen: do_action() and apply_filters()

Let’s create our own filter for a plugin which displays products. In the footer we could write: “Thanks for using our product display plugin,” which we would allow developers to modify.

Here’s how that can be done:

<p><?php apply_filters( 'product_display_footer', 'Thanks for using our product display plugin' ) ?></p>

Actions can be added the same way. You may want to allow users to add some content below the description of a product display:

<h1><?php the_title() ?></h1>
<div class="description"><?php the_content() ?></div>
<?php do_action( 'below_product_description', $post ) ?>

I’ve used the do_action() function to allow others to modify my functionality. I’ve also added the post object as the first parameter, just in case people want to add some post-specific content.


In this article we looked at the basics of hooks. We learned the difference between actions and filters and how to use them to effectively change the way WordPress works.

We also had a look at how we can add hooks of our own to our plugins and themes. This is immensely useful for making our work developer friendly.

Hooks are a part of the Plugin API, if you want to learn more about them I suggest reading the relevant pages in the WordPress Codex. The more you use hooks the more you’ll love them and appreciate the power and flexibility they offer.