Hooks are the backbone of WordPress. They enable plugin developers to “hook” into the WordPress workflow to change how it works without directly modifying the core code. This

enables users to easily upgrade to newer versions of WordPress without losing modifications. If a developer modified the core code, those edits would be lost the next time WordPress was updated. The update would overwrite all those changes. Using hooks enables you to develop plugins in separate folders apart from the core, keeping the plugin code safe from updates. Without hooks, plugins and themes would have no way to modify how WordPress works. The hooks system you learn about in this post is used throughout the book and is something you will use in nearly every plugin you create. After you learn how to use hooks, you will understand exactly why WordPress is such a powerful platform and has thousands of plugins built for its millions of users.

WordPress has two primary types of hooks: action hooks and filter hooks. The former enables you to execute a function at a certain point, and the latter enables you to manipulate the output passed through the hook. Hooks aren’t just for plugins. WordPress uses hooks internally. If you browse through the core source code, you can see many examples of how WordPress uses its own system to hook into itself.


Action hooks enable you to fire a function at specific points in the WordPress loading process or when an event occurs. For example, you might want a function to execute when WordPress first loads a page or when a blog post is saved. You need to understand the do_action() function. When hooking into WordPress, your plugin won’t call this function directly; however, your plugin will almost always use it indirectly.

You need to understand the do_action() function. When hooking into WordPress, your plugin won’t call this function directly; however, your plugin will almost always use it indirectly.


do_action( $tag, $arg = ” );


  • $tag — The name of the action hook.
  • $arg — Value(s) passed to registered actions. It looks like a single parameter, but this isn’t always the case. Action hooks have the option to pass any number of parameters or no parameters at all. You need to check the WordPress source code for specific hooks because the number of parameters changes on a per-hook basis.

Following is an example of what an action hook would look like with multiple parameters.


do_action( $tag, $arg_1, $arg_2, $arg_3 );


Now take a look at a WordPress action hook called wp_head and how it appears in WordPress. This hook is fired within the <head> area on the front end of the site. WordPress and plugins usually use this hook to add meta information, style sheets, and scripts.


do_action( ‘wp_head’ );


When this code fires in WordPress, it looks for any actions registered for the wp_head action hook. It then executes them in the order specified. As you can see, it has a name of wp_head but passes no extra parameters. This is often the case with action hooks.

Following is an example of an action hook that has two extra parameters.


do_action(‘save_post’, $post_ID, $post);


Here, you can see that the hook name is save_post and the parameters it passes are $post_ID and $post.

What Is an Action?

An action is technically a PHP function. For a function to be considered an action, it would need to be registered for an action hook. In the previous section, you can see what action hooks are, but for action hooks to serve any purpose, they need to have an action registered for them. That’s where plugins come in. You develop custom functions (actions) that perform a specific task when the action hook is fired. To do this, you would use the add_action() function.


add_action( $tag, $function, $priority, $accepted_args );


  • $tag — The name of the action hook your function executes on.
  • $function — The name of your function that WordPress calls.
  • $priority — An integer that represents the order in which the action is fired. When no value is given, it defaults to 10. The lower the number, the earlier the function will be called. The higher the number, the later it will be called.
  • $accepted_args — The number of parameters the action hook will pass to your function. By default, it passes only one parameter.

Action hooks aren’t limited to a single action. Your plugin can add multiple functions to an action hook. Other plugins, and even WordPress core, often add functions to the same hook. Now it’s time for you to put action hooks to use. One common action hook is wp_footer. It is fired on the front end of the site by the user’s WordPress theme. Generally, it is fired just before the closing </body> tag in the HTML. In this example, you’re going to register an action for the wp_footer hook that adds a custom message to the footer.


add_action( ‘wp_footer’, ‘boj_example_footer_message’, 100);

function boj_example_footer_message() { echoThis site is built using <a href=”http://themetechs.com”  title=”WordPress publishing platform”>WordPress</a>.‘;}


Code snippet boj-example-footer-message.php Take a closer look at how you used add_action() from the preceding code.


add_action( ‘wp_footer’, ‘boj_example_footer_message’, 100);


The first parameter is the name of the hook (wp_footer). The second parameter is a callback to your custom function (boj_example_footer_message). The third parameter is the priority (100). Your function will likely be executed much later than other functions hooked to wp_footer because of its priority of 100. If this number were changed to 1, it would be called earlier. It should be noted that hooks might be fired more than once in the WordPress flow for various reasons. Any actions added to these hooks will execute each time the hook is fired.


remove_action() enables you to remove an action that has previously been added to a hook. Typically, you would remove actions that WordPress adds by default. To remove an action, the action must have already been added using the add_action() function. If your code runs before the action is registered, the action will not be removed from the hook. The function returns true when the action was successfully removed and false when the action could not be removed.


remove_action( $tag, $function_to_remove, $priority, $accepted_args );



  • $tag — The name of the action hook the action you want to remove is hooked to.
  • $function_to_remove — The name of the function that has been added to the hook.
  • $priority — The priority given in the add_action() function. This defaults to a value of 1
  • $accepted_args — The number of accepted arguments the action accepts. This defaults to a value of 1.

To successfully remove an action from a hook, the $tag, $function_to_remove, and $priority parameters must exactly match the parameters used in do_action(). Otherwise, the action will not be removed and remove_action() will return false. Let’s take a look at one of WordPress’ default actions called rel_canonical. This action adds a canonical link between the opening <head> and closing </head> element on the site’s front end.


add_action( ‘wp_head’, ‘rel_canonical’ );


To remove this action, you must use the remove_action() function in your plugin. You need to define the $tag and $function_to_remove parameters. In this case, you don’t need to add the $priority parameter because no priority was explicitly given in the action previously defined.


remove_action( ‘wp_head’, ‘rel_canonical’ );


It is possible to remove any action added by WordPress, a plugin, or a theme within your plugin. Generally, you remove actions within WordPress. Many of its default actions are defined in the wp-includes/default-filters.php file. Browsing this file can give you a general overview of how WordPress uses action hooks.

Commonly Used Action Hooks

WordPress has many action hooks, but some of them are used more often than others. Knowing what these hooks are can help you lay down the groundwork for your plugins.

plugins_loaded For plugin developers, the plugins_loaded action hook is probably the most important hook. It is fired after most of the WordPress files are loaded but before the pluggable functions and WordPress starts executing anything. In most plugins, no other code should be run until this hook is fired. plugins_loaded is executed when all the user’s activated plugins have been loaded by WordPress. It is also the earliest hook plugin developers can use in the loading process. A WordPress plugin should do its setup on this hook. Other actions should also be added within the callback function used on this hook. In the following example, you use the boj_example_footer_message action you created in the previous section. Rather than calling it separately, add it to

your setup action, which is hooked to plugins_loaded.


add_action( ‘plugins_loaded’,

‘boj_footer_message_plugin_setup’ );

function boj_footer_message_plugin_setup() {

/* Add the footer message action. */

add_action( ‘wp_footer’, ‘boj_example_footer_message’,

100 );


function boj_example_footer_message() {

echo ‘This site is built using <a href=”http://wordpress.org”

title=”WordPress publishing platform”>WordPress</a>.’;



It is good practice to create a setup function and hook it to plugins_loaded. By doing this, you can ensure that you don’t inadvertently trigger any errors from a specific WordPress function not being loaded.


The init hook is fired after most of WordPress is set up. WordPress also adds a lot of internal functionality to this hook such as the registration of post types and taxonomies

and the initialization of the default widgets. Because nearly everything in WordPress is ready at this point, your plugin will probably use this hook for anything it needs to do when all the information from WordPress is available. In the following example, you add the ability for users to write an excerpt for pages. You would do this on init because the “page” post type is created at this point using the add_post_type_support() function.


add_action( ‘init’, ‘boj_add_excerpts_to_pages’ );

function boj_add_excerpts_to_pages() {

add_post_type_support( ‘page’, array( ‘excerpt’ ) );




The admin_menu hook is called only when an administration page loads. Whenever your plugin works directly in the admin, you would use this hook to execute your code.

The next example adds a sub-menu item labeled BOJ Settings to the Settings menu in the WordPress admin.


add_action( ‘admin_menu’, ‘boj_admin_settings_page’ );

function boj_admin_settings_page() {


‘BOJ Settings’,

‘BOJ Settings’,








The template_redirect action hook is important because it’s the point where WordPress knows which page a user is viewing. It is executed just before the theme template is

chosen for the particular page view. It is fired only on the front end of the site and not in the administration area. This is a good hook to use when you need to load code only for

specific page views. In the next example, you load a style sheet file only for a singular post view.


add_action( ‘template_redirect’, ‘boj_singular_post_css’ );

function boj_singular_post_css() {

if ( is_singular( ‘post’ ) ) {












On the front end of the site, WordPress themes call the wp_head() function, which fires the wp_head hook. Plugins use this hook to add HTML between the opening <head> tag and its closing </head>. In the following example, you add a meta description on the front page of the site using the site’s description.


add_action( ‘wp_head’, ‘boj_front_page_meta_description’ );

function boj_front_page_meta_description() {

/* Get the site description. */

$description = esc_attr( get_bloginfo( ‘description’ ) );

/* If a description is set, display the meta element. */


if ( !empty( $description ) )

echo ‘<meta name=”description” content=”‘ .

$description . ‘” />’;



Many plugins incorrectly use the wp_head action hook to add JavaScript to the header when they should be using the wp_enqueue_script() function. The only time JavaScript should be added to this hook is when it’s not located in a separate JavaScript file.


Filter hooks are much different than action hooks. They enable you to manipulate the output of code. Whereas action hooks enable you to insert code, filter hooks enable you to overwrite code that WordPress passes through the hook. Your function would “filter” the output. To grasp the concept of filter hooks, you must first understand how the apply_filters() WordPress function works.


apply_filters( $tag, $value );


  • $tag — The name of the filter hook.
  • $value — The parameter passed to any filters added to the hook. The function can also take in any number of extra $value parameters to pass to filters. It is important to note here that $value must be returned back to WordPress when writing a filter. Here is an example of a filter hook from the core WordPress code.


apply_filters( ‘template_include’, $template );


In this example, template_include is name of the filter hook. $template is a file name that can be changed through filters registered for the filter hook.

What Is a Filter?

A filter is a function registered for a filter hook. The function itself would take in at least a single parameter and return that parameter after executing its code. Without a filter, filter hooks don’t do anything. They exist so that plugin developers can change different variables. This can be anything from a simple text string to a multidimensional array.

When a filter hook is called by the apply_filters() function,any filters registered for the hook are executed. To add a filter, use the add_filter() function.


add_filter( $tag, $function, $priority, $accepted_args );


  • $tag — The name of the hook you want to register your filter for.
  • $function — The function name of the filter that you create to manipulate the output.
  • $priority — An integer that represents in what order your filter should be applied. If no value is added, it defaults to 10.
  • $accepted_args — The number of parameters your filter function can accept. By default this is 1. Your function must accept at least one parameter, which will be returned.

You can add multiple filters to the same filter hook. Other plugins and WordPress can also add filters to the hook. Filter hooks aren’t limited to a single filter. It is important to note this because each filter must always return a value for use by the other filters. If your function doesn’t return a value, you risk breaking the functionality of both WordPress and other plugins. Now look at the wp_title filter hook in WordPress, which is a filter hook responsible for the <title> element on a page.


apply_filters( ‘wp_title’, $title, $sep, $seplocation );


  • wp_title — The name of the hook.
  • $title — A string and the value that you want to filter and return back to WordPress.
  • $sep — A string that tells you what the separator should be between elements in the <title> element.
  • $seplocation — The location of the separator. In the next example, you don’t use it.

You’re now going to write a function that filters the output of $title by appending the site’s name to the end of page title.


add_filter( ‘wp_title’, ‘boj_add_site_name_to_title’, 10, 2 ); function boj_add_site_name_to_title( $title, $sep ) {

/* Get the site name. */

$name = get_bloginfo( ‘name’ );

/* Append the name to the $title variable. */

$title .= $sep . ‘ ‘ . $name;

/* Return the title. */

return $title; }


Take a look at the line telling WordPress to add a filter to wp_title.


add_filter( ‘wp_title’, ‘boj_add_site_name_to_title’, 10, 2 );


It says that you want to add a filter named boj_add_site_name_title_title to the wp_title filter hook. You set a priority of 10 and tell your filter to accept two parameters. The boj_add_site_name_to_title() function manipulates the $title parameter and returns it back to WordPress. The $sep parameter can be used within the function but is not returned.

Commonly Used Filter Hooks

WordPress has hundreds of filter hooks for use by plugins and themes developers. Narrowing these down to a small list of some commonly used hooks doesn’t come close to accurately representing what a plugin can accomplish by using the hook system. In this section, you learn how to use some of the more common filter hooks that plugin developers use in their plugins.


If there’s one filter hook that plugin authors use more than any other, it is the_content. Without content, a site would be essentially useless. It is the most important thing displayed on the site, and plugins use this hook to add many features to a site. The the_content hook passes a post’s content to any filters registered for it. Filters then manipulate the content, usually for extra formatting or to append additional information about the post. With the next code example, you append a list of related posts by post category to the_content for a reader to see when viewing a single post.


add_filter( ‘the_content’, ‘boj_add_related_posts_to_content’ );

function boj_add_related_posts_to_content( $content ) {

/* If not viewing a singular post, just return the content. */

if ( !is_singular( ‘post’ ) )

return $content;

/* Get the categories of current post. */

$terms = get_the_terms( get_the_ID(), ‘category’ );

/* Loop through the categories and put their IDs in an

array. */

$categories = array();

foreach ( $terms as $term )

$categories[] = $term->term_id;

/* Query posts with the same categories from the database.


$loop = new WP_Query(


‘cat__in’ => $categories,

‘posts_per_page’ => 5,

‘post__not_in’ => array( get_the_ID() ),

‘orderby’ => ‘rand’



/* Check if any related posts exist. */

if ( $loop->have_posts() ) {

/* Open the unordered list. */

$content .= ‘<ul class=”related-posts”>’;

while ( $loop->have_posts() ) {


/* Add the post title with a link to the post. */

$content .= the_title(

‘<li><a href=”‘ . get_permalink() . ‘”>’,





/* Close the unordered list. */

$content .= ‘</ul>’;

/* Reset the query. */



/* Return the content. */

return $content;




Code snippet boj-related-posts.php


Post titles are almost as important as the post content, which makes the_title a popular filter hook for use. You can use this hook to add information or overwrite completely. One useful filter to use for the_title is a function to strip HTML tags from it. Users sometimes add tags here that can mess up the formatting of the title on output. Using the following code, you can strip all tags a user might use when writing a post title.


add_filter( ‘the_title’, ‘boj_strip_tags_from_titles’ );

function boj_strip_tags_from_titles( $title ) {m$title = strip_tags( $title );

return $title;




The comment_text hook is often a useful filter hook because comments typically play a large role for blogs and other types of sites. With the next code example, you check if a comment was made by a registered user on the site. If the user is registered, you can append a paragraph that prints the user’s role for the site.


add_filter( ‘comment_text’, ‘boj_add_role_to_comment_text’ );

function boj_add_role_to_comment_text( $text ) { global $comment;

/* Check if comment was made by a registered user. */

if ( $comment->user_id > 0 ) {

/* Create new user object. */

$user = new WP_User( $comment->user_id );

/* If user has a role, add it to the comment text. */

if ( is_array( $user->roles ) )

$text .= ‘<p>User Role: ‘ . $user->roles[0] . ‘</p>’;


return $text;




template_include is a sort of catchall filter hook for many other, more specific filter hooks.

  • front_page_template
  • home_template
  • single_template
  • page_template
  • attachment_template
  • archive_template
  • category_template
  • tag_template
  • author_template
  • date_template
  • archive_template
  • search_template
  • 404_template
  • index_template

It is used after the theme template file for the current page has been chosen. WordPress chooses a template based on the page currently viewed by a reader. You can add a filter for each of the individual filter hooks or filter them all at the end with the template_include hook.

Suppose you wanted to build a custom template hierarchy to allow themes to use templates based on your plugin’s criteria instead of the normal WordPress template hierarchy. The template_include and the other hooks in the previous list enable you to do this.

 Using the next example code, you check if a template exists for single posts by category. By default, WordPress looks for a single.php file first and then falls back to index.php if it doesn’t exist. Your function looks for a file called single-category-$slug.php ($slug is the category slug), so if a user has a category with the slug of “art” and a template

named single-category-art.php in their theme, this file will be used in lieu of single.php.



add_filter( ‘single_template’, ‘boj_single_template’ );

function boj_single_template( $template ) {

global $wp_query;

/* Check if viewi/* Get the post ID. */

$post_id = $wp_query->get_queried_object_id();

/* Get the post categories. */

$terms = get_the_terms( $post_id, ‘category’ );

/* Loop through the categories, adding slugs as part of the file name. */

$templates = array();

foreach ( $terms as $term )

$templates[] = “single-category-{$term->slug}.php”;

/* Check if the template exists. */

$locate = locate_template( $templates );

/* If a template was found, make it the new template. */

if ( !empty( $locate ) )

$template = $locate;


/* Return the template file name. */

return $template;




Code snippet boj-single-template.php


So far, you’ve seen many examples of using action and filter hooks with PHP functions. When adding a method of a class as an action or filter, the format of the calls to add_action() and add_filter() is slightly different. In general, plugins most often use functions as actions and filters rather than class methods. However, there will be cases in which using a class will be beneficial to your plugin, and you will need to know how to register methods for hooks from within the class. Take a look at a basic function registered for an action hook, which was covered in detail in the section on actions earlier in the chapter.


add_action( $tag, $function_to_add );


When using a method such as $function_to_add from within a class, you must change $function_to_add to an array with &$this as the first argument and the method name as the second argument.



add_action( $tag, array( &$this, $method_to_add ) );



The same is true for filter hooks as well. A function added to a filter hook would normally look like this:


add_filter( $tag, $function_to_add );


When using a class method as a filter, you must also change the $function_to_add parameter.


add_filter( $tag, array( &$this, $method_to_add ) );