Hooks

This article is part of the WordPress guide. Read the introduction.

As previously noted, hooks are the most significant part of WordPress’s architecture. They provide a way to interact with/modify code in predefined spots. They are the foundation for themes and plugins to interact with the WordPress core. They work by registering callbacks to be executed when the hook is called. There are 2 types of hooks – actions and filters.

Actions

Actions provide a way to run code at specific points in the execution. Here’s how you hook your function to an action:

add_action( $hook_name, $callback, $priority = 10, $accepted_args = 1 );

$hook_name is the name of the action you’re hooking into. WordPress comes with hundreds of actions in the core itself, and you have to choose the appropriate one based on where you want your function to run. $callback is the name of your callback function.

You can specify the relative priority of your function with the $priority argument. The lower the priority, the earlier your callback will be run. Theoretically, there is no lower or higher bound on priority. That being said, it’s best practice to only use priorities between 1 and 20. Using a negative priority is rare, but can be useful in advanced scenarios, where you have to guarantee your function runs before all others (most functions will keep the default priority of 10 anyway).

The $accepted_args argument indicates the number of parameters you want the action to pass to your callback function. A hook can, and often does, pass some data to the callback. Let’s look at the ‘save_post’ action. It passes 3 parameters – $post_id, $post (WP_Post object), and $updated (bool). If you want to use the last 2, you’d have to explicitly set $accepted_args = 3, and make your callback function accept 3 parameters.

Thankfully, php doesn’t care if you pass too many parameters to a function, which is why the default value of 1 doesn’t cause errors if your callback doesn’t accept any parameters. How do you know what parameters are passed by a given hook? You look at the official WordPress Hooks Reference (or at the source code).

An example use of add_action():

PHP
function callback_on_save( $post_id, $post, $updated ) {
	// Some code
}
add_action( 'save_post', 'callback_on_save', 10, 3);

do_action( $hook_name, $args… );

The do_action() function executes all the callbacks hooked to the specified action in the correct order of priority. The parameters to be passed to callbacks are specified after the hook name. Here’s what the code for ‘save_post’ looks like:

PHP
// Define $post_id, $post, and $updated
do_action( 'save_post', $post_id, $post, $updated );

The entire WordPress code has hundreds of those do_action() calls scattered across the entire core. They are strategically placed to let plugin and theme developers do something before or after something significant happens.

You can also define your custom actions with this function. The only thing you need to do is use it with a unique name, like do_action( ‘my_theme_action’ ). It doesn’t require any sophisticated registering of a hook name or anything. Just call do_action() and any callback that has been registered with this hook name will get executed in that place.

Filters

Filters provide a way to modify some piece of data. Unlike actions, filters are supposed to work in an isolated manner and should not have any side effects, such as affecting global variables or throwing exceptions.

add_filter( $hook_name, $callback, $priority = 10, $accepted_args = 1 );

The idea is the same as for add_action(). As a matter of fact, you can see the arguments are exactly the same. It’s what happens with the callback that differs.

The purpose of the filter is to pass some data to the callback, and then receive a “filtered” version of that data in response. That means all of the filters will pass in at least one parameter. This is where the default value of $accepted_args comes in handy. Filters can pass more parameters, just like actions.

The callback has to return a value. The returned value becomes the new, updated value for the variable being filtered. This modified value is then passed to the next filter in the order of priority.

An example use of add_filter():

PHP
function add_exclamation_mark_to_title( $title ) {
	return $title . '!';
}
add_filter( 'the_title', 'add_exclamation_mark_to_title' );

apply_filter( $hook_name, $value, $args… );

This is the do_action() equivalent for filters. It executes the callbacks hooked to $hook_name, passing in the original $value and optional additional $args. Just as with actions, you can define your own filter by calling apply_filter() with a unique hook name.

Removing Actions And Filters

Sometimes you might want to remove an action or filter registered by a theme, plugin, or even WordPress core itself. You can do that with remove_action() or remove_filter(). The $callback and $priority passed to those functions have to be the same as those used for registering the action/filter. You can only remove the action/filter after it is added – the order of execution matters. Here’s how you could remove the previously registered functions:

PHP
function remove_custom_callbacks() {
	remove_action( 'save_post', 'callback_on_save', 10 );
	remove_filter( 'the_title', 'add_exclamation_mark_to_title' );
}
// use after_setup_theme to guarantee execution after the original hooks have been added
add_action( 'after_setup_theme', 'remove_custom_callbacks' );