What are WordPress Hooks? Actions, Filters and Custom Hooks Explained

WordPress hooks help you to modify the code, add functionality to a website, and change the way data is rendered on the front end without changing the WordPress core or digging too deep into the structure of the theme or plugins (which, by the way, use hooks a lot, too).

Let’s imagine a WordPress core, along with themes and plugins, as a machine with many interconnected gears and hooks (in a general sense of this word). So, if we want to change or upgrade something in this machine, we can either hang our function on an existing hook or create our custom hook – so it will be executed at the specific point in the overall sequence. 

Hooks can also be compared with checkpoints or bus stops when the bus driver (WordPress) checks at those stops (hooks) if someone needs to be picked up (hooked functions).  

Table of Contents

What Are WordPress Hooks?

Hooks are small pieces of code aimed to modify another code. They can be easily added and removed, so the code can be customized without modifying the core and making a mess there. So, it’s a really powerful and handy feature that makes WordPress as expandable and flexible as it is.  

Hooks either add some data or functionality to the core, theme, or plugin and perform some actions at a specific time (before, after, or while another action is taking place) or modify (filter) data before it is stored in the database or rendered to the front end.

The first type is called action hooks, and the second is filter hooks.

Hooks actually “hook” or “pin” a certain function to a certain place of the template or on a certain event in WordPress runtime. So, we can write a function and then call the hook somewhere where (and when) we need it several times if required.

A lot of hooks can be found in different PHP files of the theme or core. But when a person who is not a WordPress core or theme developer adds hooks to the existing site, they should place them either in the functions.php file of the child theme (this is important; otherwise, you will lose them when updating the theme!) or in a custom plugin created solely for hooks.  

Some details and examples

Hooks are part of WordPress Plugin API, and in the WordPress documentation, you can find the list of WordPress existing core hooks that you can use to make your code run at a specific point in runtime. 

Also, there’s a list of functions that deal with hooks; you can find it on the Codex page

Registering custom post type by writing a hook

For example, in the list of core hooks (on the link above), we can find the init hook registered deep in the WordPress core, and what we need to know about it is the point in the WordPress render process at which it will fire. And Codex gives us the answer: “Fires after WordPress has finished loading but before any headers are sent.”

So, it’s a perfect candidate to “hang” some functions to this hook, for example, to register a custom post type:

    // Register Custom Post Type My_Cool_CPT
function create_my_cool_cpt() 

    $args = array(
       // your array of args goes here
    $labels = array(
        // the nested array of labels goes here
    register_post_type( 'mycoolcpt', $args );

add_action( 'init', 'create_my_cool_cpt', 0 );

(By the way, if you want to easily generate argument arrays which I’ve omitted here so as not to clutter up this code snippet, just use one of the online generators like this).

So, the code above adds some action (the action of adding a custom post type, in this case). 

There are two logical parts in this piece of code:

  1. Details about the new custom post type (CPT): a custom function that I named “create_my_cool_cpt,” which determines all the details about this CPT, and a built-in WordPress PHP hook, “register_post_type.”
  2. The “add_action” built-in WordPress function is used to attach the custom function to the specific action (or, in other words, a hook to hang our custom code on it).

Let’s look closer at the structure of add_action: the function that I want to attach – or callback – (‘create_my_cool_cpt’) is passed as the second parameter, and the action to which I want to attach it (‘init’) is passed as the first parameter. Both of those parameters are required. 

Zero at the end shows the priority (0=the highest priority); this parameter is optional. 


If you got confused about what can be actually named a hook: what is already registered in the core, by theme or plugin, or the code snippets we add, the answer is that in common use, they both are called “hooks.”
In other words, we can hook our hooks to the existing hooks, create our own, and hook something to them. 😅

Finding all the hooks on your website 

There are the most typical action events that are taking place when the site loads, so many action functions can be hooked into them:

Action core hooks

You can find the bigger list in Plugin API Action Reference (for actions) and Plugin API Filter Reference (for filters). 

But to see all the hooks that exist on the website pages (that core, your theme, plugins have, plus custom ones), you can use plugins that show them, e.g., Another Show Hooks. It looks quite scary when you switch it on, but it gives a lot of important information and even more details on hover:

Show WordPress hooks

I’ve already written how you can use this tool and hooks to customize WooCommerce pages

But also, to “play” with them, you can write the most simple action hook (I made the dummy text bold and red to be even more visible):

function my_hi_there_function() 
      echo "<p style="color:red;font-weight:800;">Hi there! I am your hook</p>";

add_action( 'generate_after_entry_title', 'my_hi_there_function' );
adding action hooks WP

I’ve hooked it to “generate_after_entry_title” so that the text is displayed after each title. You can insert a useful function and pin it there instead of this text. This echo function is just for showing visually where exactly your code will fire. 

Types of WordPress Hooks

As mentioned earlier, there are two types of hooks: actions and filters. Let’s have a closer look at each of them. 

Actions (action hooks)

Actions are used to do something in the process of WordPress runtime – it fires at the moment certain existing processes of WordPress core, theme, or plugin are being executed; it does it at the specified point of this process flow and then just goes back to normal. Its callback function doesn’t return anything to the calling action hook.

These built-in functions are most frequently used with actions:

  • add_action attaches a certain callback function to a certain hook or hook name (as in the example in the paragraph above).
    Syntax: add_action( $hook, $function_to_add, priority, accepted_args );
  • remove_action detaches the callback function that has been attached to the hook earlier with add_action.
    Syntax: remove_action( $hook, $function_to_remove, priority );
  • do_action is used for creating custom action hooks; it calls the callback function added to the matching action hook.
    Syntax: do_action( $hook_name, $arg ).

Custom action hooks

Let’s say I need to display the text “Look, this is my website’s URL” in various places on the site. Not somewhere where the WordPress core, my theme, or plugins already have hooks, but exactly where/when I want. So, a custom hook is needed. 

I will call it “my website link” and first will write a callback function “my_link_echo” that will be attached to this hook (to set what will actually happen once my custom hook is executed). So, in functions.php, I will add this:

add_action( 'my_website_link', 'my_link_echo', 10, 1 );
    function my_link_echo( $url )
        echo "Look, this is my favorite URL -- <a href= '$url'>$url</a>";

And now I can register my custom hook where I want:

do_action( 'my_website_link', home_url( '/' ) );

As you can see, it passes only one, the “home_url” argument – one is just a default number of arguments. If more than one argument is passed, then this number should be changed and equal to the required number of arguments. 

If I want to see it before the main footer, I will place it here:

using do_action WP

If I want to see it somewhere else, I should also insert it there. The “home_url()” has an argument in brackets that is passed there, which means that it can be changed in every place I use it. 

For instance, in the footer, I will use the home URL (‘/’), and at the top of each post, I want to use a link to the blog archive, so I will simply change the argument to the blog URL and add do_action in single.php (a template for posts):

where to insert do_action

If I or someone else later wants to execute any other callback function, they can pin it to my “my_website_link” function, and it will be fired at both places or wherever this hook (starting with do_action();) is called. 

If there will be many callback functions pinned to the same hook, it’s better to change their priority values from the default value is 10 to the order you want them to fire. 

Let’s look at one more example – using a WordPress built-in hook and then adding a custom hook to it. 

For starters, what if I want to keep the post called “Logged Only” only for logged-in users, and the rest should be redirected to the home page? This is what I need: 

    add_action ('template_redirect', 'logged_only');
    function logged_only()
        if(is_single('logged-only') && !is_user_logged_in() )   
            wp_redirect(home_url() );

Here, I use the built-in hook “template_redirect,” which fires before it’s determined which template to load. I added my callback “logged_only” and used the function wp_redirect().”

What if I want to add my custom hook, which will add information to the log file each time someone attempts to access the Logged Only page? It should write, “Someone just tried to access Logged Only page on” and add the date and time of the attempt. The log will be stored in the access_log.txt file, which I’ve already created. 

add_action ('template_redirect', 'logged_only');
    function logged_only()
        if(is_single('logged-only') && !is_user_logged_in() ) 
            do_action( 'write_to_log', date("F j, Y, g:i a")); //date is an argument here
            wp_redirect(home_url() );
add_action( 'write_to_log', 'log_when_accessed' );
    function log_when_accessed($date) 

        $access_log = get_stylesheet_directory() . '/access_log.txt';
        $message="Someone just tried to access Logged Only page on " . $date;
    if( file_exists( $access_log) ) 
        $file = fopen( $access_log, 'a' ); //a PHP function where "a" means that message is placed at the end of the file
        fwrite($file, $message."\n"); //\n says it will be written from a new line
            $file = fopen( $access_log, 'w' ); //attempts to create a file if it doesn’t exist
            fwrite($file, $message."\n");

Filters (filter hooks)

Filters are very similar action hooks: they fire at a certain moment during the WordPress runtime, they have a similar code structure, etc. But there are at least two differences that should be named:

  1. Filter hooks always return something: because filters are literally filtering and modifying content, they should return filtered/modified content. So, the callback code always has the word “return.
  2. The whole idea of filters is different from the idea of actions. While actions interfere with the whole process of site render, filters work independently. They are like workers of a theatre backstage who prepare props and costumes without being in the spotlight and reveal the results of their work only when required – while actions can be compared with actors on stage. 

These built-in functions are most frequently used with filters:

  • add_filter hooks a callback function to the certain filter hook.
    Syntax: add_filter( $hook_name, $callback, priority, accepted_args );
  • remove_filter detaches a callback function from the certain hook.
    Syntax: remove_filter( $hook_name, $callback, priority );
  • apply_filters calls a callback attached to the filter hook. 
    Syntax: apply_filters( $hook_name, $value, $args ).


In some cases, both actions and filters can be used to accomplish the same task.

Filter hooks examples

Probably one of the easiest filters is the one that returns the custom excerpt length:

    add_filter( 'excerpt_length', 'short_excerpt' );
        function short_excerpt ( $length)   
            $length = 125;
            return $length;

Where “excerpt_length” is a default WordPress core hook with a standard value of 55 characters. Using the simple code above, I’ve changed it to 125. 

And this is an example for understanding how apply_filters work; it will return a discounted price which is 10% cheaper in the product_price_filter widget:

function modify_product_price($price) 
    return $price * 0.9;

$product_price = 100;
$discounted_price = apply_filters('product_price_filter', $product_price);

echo "Original Price: $product_price";
echo "Discounted Price: $discounted_price";
add_filter('product_price_filter', 'modify_product_price');


What are WordPress functions?

For most of the core files, WordPress uses PHP language, which has a lot of built-in functions, but there are also WordPress functions in Codex Function Reference

How many types of WordPress hooks exist?

There are two types of hooks: actions and filters. Actions create an event and execute a function at a particular point of the WordPress runtime. It may or may not pass data; also, they don’t return anything. In contrast, filters modify data used by other functions and always return something. 

Wrapping Up

Hooks are what makes WordPress so flexible and expandable. Understanding how they work is essential for all those who want to have an idea of how WordPress works “under the hood” and be able to customize it. 

Leave a Reply