WordPress Hooks (Filters and Actions)

In this article, I have gathered all the basic information about WordPress hooks. I will also try to explain how hooks work in the simplest way possible. The principle of hooks is not complicated, but not everyone understands it well, and this is a big omission because hooks are a very powerful tool for changing the behavior of the WP core, creating plugins, and themes.

There are two types of hooks:

Changes the value of a variable - gets the value and returns it (changed or not).
Triggers arbitrary code - a callback function attached to the hook will run when the hook is triggered in the code.

PHP functions are attached to hooks (filters or actions), they are also called callbacks, and then these functions will run when the hook is triggered. This behavior in programming is called Hooking.

Parameters (additional data) can be passed to the function attached to the hook. Based on this data, you can create some logic. Read below.

Simple example of an action hook:

// create a function for the action hook
function echo_1(){
	echo 'Hello';

// attach the function to the hook
add_action( 'my_hook', 'echo_1' );

// create/use/trigger the hook
do_action( 'my_hook' ); //> will output "Hello" on the screen

Example with passing a parameter:

// create functions for actions
function echo_1( $data ){
	echo $data[0] .' '. $data[1] .'!';

// attach functions to the hook
add_action( 'my_hook', 'echo_1' );

// create/use/trigger the hook
do_action( 'my_hook', [ 'Hello', ' world' ] ); //> will output "Hello world!"

In the programmatic part, filters and actions are the same, i.e., in the code, both work the same way. For example, you can replace the function add_filter() with add_action() - everything will work! The distinction is necessary because they are different things in meaning.

See the list of all WP hooks on the page “All WordPress Hooks”.

There are about 2000 of them in WordPress. I have described and continue to describe some important hooks, they are located here.

How Filters Work in WordPress

Two functions are used to work with a filter:

  1. add_filter( hook_name, function, priority, args_num ) - adds/attaches a function to the filter, which will be called when the filter is triggered. Such a function is called a "callback function".

  2. apply_filters( hook_name, value, args... ) - creates a filter hook. Triggers the attached callback function.

At the time the hook is triggered, only the callbacks that have already been added will be executed. That is, you need to attach the callback before the filter is called using apply_filters().


// callback function
function my_filter_function( $str ){
	return 'Hello '. $str;

// Attach the callback to the filter.
add_filter( 'my_filter', 'my_filter_function' );

// Call the filter
$name = apply_filters( 'my_filter', 'Vladimir' );

echo $name; //> Hello Vladimir

Another example

Suppose we have a function text() that returns text. We need to make it possible to change this text outside of this function. To do this, we will name our filter my_filter_name and create a hook:

function text( $text ){

	// remove html tags from the text
	$text = strip_tags( $text );

	// return the text through the filter.
	return apply_filters( 'my_filter_name', $text );

// callback function
function my_filter_function( $text ){

	// truncate the text to 30 characters
	return mb_substr( $text, 0, 30 ) .'...';

// Attach the function to the filter
add_filter( 'my_filter_name', 'my_filter_function' );

// Call text()
// the function will remove html tags from the text - it will do this itself using strip_tags().
// And then it will truncate the text - our filter will do this

$text = 'Lorem <b>Ipsum</b> is simply dummy text of the printing and typesetting industry.';

echo text( $text );

// will output:
// Lorem Ipsum is simply dummy te...

There are many filters in WordPress, and you have probably encountered them in themes and plugins. Some popular ones are: the_content, body_class, sanitize_user, comment_form.

How Actions Work in WordPress

Two functions are used to work with an action:

  1. add_action( hook_name, function, priority, args_num ) - adds/attaches functions to the action, which is called using do_action(). The function must be attached to the action before the action occurs. This is necessary so that when the action is triggered, the PHP functions are already attached to the action.

  2. do_action( hook_name, args... ) - this is the action. Triggers/calls the functions attached to the action. It is called where the action should occur.

do_action() should be called after add_action(), i.e., after a function is added to the action, which is logical...


Suppose we are creating a theme and in some part of the theme, we need to call a function, but we don't know in advance what the function will be called. i.e., users will add the function themselves to this place.

For this, in this part of the template, we can call not a function but an action, let's call it my_action and then attach a function to this action:

// create a function for the action
function my_action_function( $text ){
	echo 'The "my_action" event has just occurred.';
// Attach the function to the 'my_action' action. This can be done in another file
// the main thing is to do it before the event occurs.
add_action( 'my_action', 'my_action_function' );

// Call the action itself. Insert this line into the place in the theme where it is needed,
// for the attached function to be triggered
do_action( 'my_action' ); //> the message 'The "my_action" event has just occurred.' will be output at this code location

You have also encountered actions, there are many of them, and some of the most popular ones are: wp_head, wp_footer.

Priority of a Hook

The priority is important when multiple callback functions are attached to a hook. The priority determines the order in which the callback function will be executed in relation to other callback functions.

The priority is specified in the third parameter for the function that attaches the function to the hook:

add_action( 'init', 'hook_callback1', 8 );
add_action( 'init', 'hook_callback2', 9 );

The function with priority 8 will be executed before the function with priority 9. If the priority is not specified, it defaults to 10 - the default priority.

If two functions are attached to the same hook with the same priority, they will be executed in the order they were attached.

Let's look at how priorities work in an example:

add_action( 'init', 'run_me_late', 11 );
add_action( 'init', 'run_me_early', 9 );
add_action( 'init', 'run_me_normal' );     // default priority 10
add_action( 'init', 'run_me_normal_two' ); // default priority 10

At the time the init hook is triggered, the functions will be executed in the following order:

  1. run_me_early()
  2. run_me_normal()
  3. run_me_normal_two()
  4. run_me_late()
  • As you can see, the higher the priority number, the later the hook will be executed.

  • If the priority is not specified, as in the first example, it defaults to 10.

The priorities work exactly the same for filters.

Parameters of a Hook

Some data - parameters can be passed to the attached callback function. You can use them at the time the hook is triggered to create some logic.

For example, when WordPress saves a post, the save_post event is triggered. This hook can pass two parameters: post ID and post object:

do_action( 'save_post', $post->ID, $post );

By default, only the first parameter $post->ID is passed:

add_action( 'save_post', 'my_save_post_callback' );

function my_save_post_callback( $post_id ) {
	// only one parameter is available

However, you can specify that we want to receive 2 parameters. To do this, specify the fourth parameter in add_action():

add_action( 'save_post', 'my_save_post_callback', 10, 2 );

function my_save_post_callback( $post_id, $post ) {
	// 2 parameters are available

The limitation to one parameter by default is made for the performance of the hook system.

For filters, everything works in a similar way

When creating a filter, you can pass any number of parameters separated by commas:

$str = apply_filters( 'my_filter', $str, $data1, $data2 );

Now, when adding the callback, we can use these parameters. To do this, specify the number of parameters to be passed:

add_filter( 'my_filter', 'my_filter_function', 10, 3 );

The filter function will look like this:

function my_filter_function( $str, $data1, $data2 ){

	// We can use $data1, $data2

	return $str;

Removing a Hook

To remove a hook, you need to modify the source code and delete the hook call, which is usually impossible because the hooks are located in the core or in a plugin. Here we will talk about how to remove callback functions attached to a hook.

To remove a function attached to a filter/action, one of the following functions is used:

For reference. These are completely identical functions and both of them remove the hook, whether it is a filter or an action, in this case, it doesn't matter. For example, we can remove both actions and filters using only the remove_filter() function or only the remove_action() function. However, for code clarity, it is still better to remove filters using remove_filter() and actions using remove_action().

To remove a hook, you need to know:

  1. The hook name, for example, wp_footer.
  2. The name of the attached function, for example, my_action_function.
  3. The execution priority of the hook, if it was set when the hook was created. If the priority was not set when the hook was created, it is equal to 10 and is not required to be specified when removing it.

    If you need to remove a hook with a priority other than 10 and you did not specify it, the hook will NOT be removed!

Example of Removing a Hook

Suppose somewhere in a plugin, the function my_action_function is attached to the wp_footer action, which outputs text in the theme footer:

add_action( 'wp_footer', 'my_action_function' );

function my_action_function( $text ){
	echo 'This is the text in the footer!';

In the theme, we need to remove this action so that the text in the footer is not displayed. To do this, you can add the following code to the theme's functions.php file:

remove_action( 'wp_footer', 'my_action_function' );

Important: The hook should be removed after it is added, but has not yet been executed.

Another Example of Removing a Hook

Demonstration of adding and removing a hook:

// add a function to the my_action action
add_action( 'my_action', 'my_action_function' );

function my_action_function( $text ){
	echo 'Hello!';

// create the action
do_action( 'my_action' ); //> Hello!

// remove the previously added action
remove_action( 'my_action', 'my_action_function' );

// create the action again
do_action( 'my_action' ); // will not output anything...

Removing with consideration of priority

The priority must match the one that was set when the hook was added.

// if added like this
add_filter( 'my_filter', 'function_name', 99 );

// then it should be removed like this
remove_filter( 'my_filter', 'function_name', 99 );

Removing a hook of a static method of a class

// added like this
add_filter( 'my_filter', [ 'My_Class', 'static_method_name' ], 15 );

// it should be removed like this
remove_filter( 'my_filter', [ 'My_Class', 'static_method_name' ], 15 );

Removing a hook of a non-static method of a class (if there is access to $this - an instance of the class)

class A {

	function __construct(){
		add_action( 'my_action', [ $this, 'method_name' ], 15 );

	function method_name(){
		echo 'Hello!';

$class = new A(); // instance

// to remove, you need to find the variable in which the
// class instance was saved when created, in this case it's $class
remove_action( 'my_action', [ $class, 'method_name' ], 15 );

Removing a hook of a non-static method of a class (if there is NO access to $this - an instance of the class)

It is impossible to remove a hook for an object of a class to which you do not have access using standard WP functions. However, you can do this using the following custom functions:



 * Remove Class Action Without Access to Class Object
 * @see remove_object_filter()
function remove_object_action( string $hook_name, $static_callback, $priority = null ): bool {
	return remove_object_filter( $hook_name, $static_callback, $priority );

 * Remove filters without access to class object (instance).
 * To use remove_filter() function you need to have access to class instance,
 * or the filter should be added using static method as hook callback.
 * This function allows you to remove filters with callbacks you don't have access to.
 * @param string       $hook_name          Filter name to remove.
 * @param string|array $static_callback    Hook callback where instance represented as class name.
 *                                         Eg: [ '\Space\My_Class', 'my_method' ] OR '\Space\My_Class' to remove all methods added to hook.
 * @param int|null     $priority           (optional) Priority of the filter. If not set all hooks with any priority will be removed.
 * @return bool Whether the hook is removed.
 * @requires WP 4.7+
 * @author   Kama (wp-kama.com)
 * @version  2.0
function remove_object_filter( string $hook_name, $static_callback, $priority = null ): bool {
	if( is_string( $static_callback ) ){
		// '\Space\My_Class::my_method' or '\Space\My_Class'
		$static_callback = explode( '::', $static_callback ) + [ '', '' ];

	$found = _find_hook_callback_instances( $hook_name, $static_callback, $priority );

	$res = 0;
	foreach( $found as $item ){
		$callback = [ $item['instance'], $item['method'] ];
		$res += (int) remove_filter( $hook_name, $callback, $item['priority'] );

	return (bool) $res;

 * Finds the instance of the object whose specified method is added for the specified hook.
 * To use remove_filter() function you need to have access to class instance,
 * or the filter should be added using static method as hook callback.
 * This function allows you to find class instance that was used when the hook was added.
 * @param string       $hook_name          Filter name.
 * @param string|array $static_callback    Hook callback where instance represented as class name.
 *                                         Eg: [ '\Space\My_Class', 'my_method' ]
 *                                         or [ '\Space\My_Class' ] to get all methods added for the hook.
 * @param int|null     $priority           (optional) Priority of the filter.
 * @return array{ instance: object|string, method:string, priority:int }[]
 * @author  Kama (wp-kama.com)
 * @version 1.1
function _find_hook_callback_instances( string $hook_name, array $static_callback, $priority = null ): array {
	global $wp_filter;

	/** @var \WP_Hook $wp_hook WP hooks. */
	$wp_hook = $wp_filter[ $hook_name ] ?? null;

	if( empty( $wp_hook->callbacks ) ){
		return [];

	$find_class_name = ltrim( $static_callback[0], '\\' ); //> \Space\My_Class >>> Space\My_Class
	$find_method_name = $static_callback[1] ?? '';

	$found = [];
	foreach( $wp_hook->callbacks as $the_priority => $hooks_data ){
		foreach( $hooks_data as $hook_data ){
			$real_callback = $hook_data['function'] ?? null;
			if( ! is_array( $real_callback ) ){

			[ $object, $the_method_name ] = $real_callback;
			$class_name = is_object( $object ) ? get_class( $object ) : $object;

				$class_name !== $find_class_name
				|| ( $find_method_name && $the_method_name !== $find_method_name )
				|| ( null !== $priority && $the_priority !== $priority )

			$found[] = [
				'instance' => $object,
				'method' => $the_method_name,
				'priority' => $the_priority,

	return $found;

Usage example.

Suppose we have the following class:

namespace My\Space;

class MyClass {

	public function __construct() {
		add_action( 'some_action_hook', [ $this, 'my_method' ], 11 );
		add_filter( 'some_filter_hook', [ $this, 'my_method' ], 11 );

	public function my_method() {
		die( 'my_method triggered: '. current_filter() );

We initialized the class, as a result of which 2 hooks were added:

new \My\Space\MyClass();

Now, it will be impossible to remove the hooks of this class using standard WP functions because to remove a hook, we need to have access to a specific instance of the class, which we do not have. However, thanks to the above functions, we can do this simply by specifying the class name, method, and priority.

Let's consider all the options for calling the function to remove the hook:

remove_object_action( 'some_action_hook', [ 'My\Space\MyClass', 'my_method' ], 11 );
remove_object_action( 'some_action_hook', [ '\My\Space\MyClass', 'my_method' ], 11 );
remove_object_action( 'some_action_hook', [ '\\My\\Space\\MyClass', 'my_method' ], 11 );
remove_object_action( 'some_action_hook', [ \My\Space\MyClass::class, 'my_method' ], 11 );
remove_object_action( 'some_action_hook', '\My\Space\MyClass::my_method', 11 );
remove_object_action( 'some_action_hook', 'My\Space\MyClass::my_method', 11 );

// or similarly for filters
remove_object_filter( 'some_filter_hook', [ 'My\Space\MyClass', 'my_method' ], 11 );
// etc...

Or if we need remove all hooks no metter what prioritet is, we may skip $priority parameter:

remove_object_action( 'some_action_hook', [ 'My\Space\MyClass', 'my_method' ] );

Removing a hook added by an anonymous function (closure)

It is not so easy to remove a hook with a closure. For example, the following code will not work:

add_action( 'my_action', function(){  echo 'Hello!';  } );

remove_action( 'my_action', function(){  echo 'Hello!';  } ); // does not work!

To reliably remove a hook using a closure, you can only do it if the closure was created in a variable and we have access to that variable:

$my_func = function(){
	echo 'Hello!';

add_action( 'my_action', $my_func );

remove_action( 'my_action', $my_func ); // It works!

A less reliable, but still a way to remove a hook with a closure when we do not have access to the closure:

 * Removes the hook when it has been added by a closure.
 * The accuracy of the function is not guaranteed - the first hook
 * that matches the priority and the number of hook arguments will be removed.
 * @param string $name
 * @param int    $priority
 * @param int    $accepted_args
function remove_closure_hook( $name, $priority = 10, $accepted_args = 1 ): bool {
	global $wp_filter;

	if( empty( $wp_filter[ $name ]->callbacks[ $priority ] ) ){
		return false;

	$callbacks = & $wp_filter[ $name ]->callbacks[ $priority ];

	// Find our hook.
	// It is not always possible to identify it unambiguously, but
	// at least we know that it was created with a closure
	// and we know it's priority and number of parameters.
	foreach( $callbacks as $key => $hook ){

		if( ! ( $hook['function'] instanceof Closure ) ){

		if( $hook['accepted_args'] !== $accepted_args ){

		// remove
		unset( $callbacks[ $key ] );

		// first suitable only
		return true;

	return false;

Usage example:

add_action( 'my_action', function(){
	echo 'Hello!';
} );

do_action( 'my_action' ); // Hello!

remove_closure_hook( 'my_action', 10, 1 );

do_action( 'my_action' ); // (empty)

Creating your own hook

When writing a plugin, you can and should add hooks to it to allow users to integrate into the plugin's code without modifying the plugin's code itself. By attaching callbacks to your hook, users of your plugin will be able to modify its code from the code of another plugin or theme.

To create an event or filter in the code to which functions can be added later, the following functions are used:

The syntax for these functions is as follows:

do_action( $tag, $arg_a, $arg_b, ... );

apply_filters( $tag, $value, $arg_a, $arg_b, ... );
$tag(string) (required)
The name of the hook.
$value(string/array/number/object/boolean) (required)
The value to be passed to the function as its first argument – the value that needs to be filtered.
The value of the argument.
The value of another argument.
Example of creating a hook event

Suppose we have a polling plugin and it would be good to add an event for this voting. This would allow other code to connect to our plugin and, for example, when voting, record some user data in their database. This functionality may not be provided by the plugin, but it may be useful for users of your plugin, and with a hook, they can easily add it.

So, we have a plugin function add_vote() - it records the vote, and at the end of this function, we will add an event:

function add_vote(){

	// function code
	// here the poll ID is determined - $poll_id and the selected answer - $answer
	// pass this data to the hook.

	// create a hook
	do_action( 'my_plugin_add_vote', $poll_id, $answer );

Now, a theme developer or another plugin developer can use this hook and perform the necessary actions at the time of the event.

add_action( 'my_plugin_add_vote', 'my_add_vote_logic', 10, 2 );

function my_add_vote_logic( $poll_id, $answer ){
	global $wpdb;

	// write to the log table, note that someone voted
	$wpdb->insert( $wpdb->log_table, [
		'user_id' => 5,
		'log_message' => 'Voted for poll '. $get_poll( $poll_id )->name
	] );


WordPress Hook Functions

do_action() Creates an event (a hook for a php function). For the function to work during the action, it should be added to this action with add_action().
do_action_ref_array() Creates an action (hook) on which PHP functions can then be attached. The arguments are passed as an array.
do_action_deprecated() Fires functions attached to a deprecated action hook.
add_action() Hooks a function on to a specific action.
remove_action() Removes a function from a specified action hook.
remove_all_actions() Removes all of the callback functions from an action hook.
did_action() Retrieve the number of times an action (hook) is fired.
current_action() Retrieves the name of the current action hook.
doing_action() Retrieve the name of an action currently being processed.
has_action() Check if any action has been registered for a hook.
apply_filters() Call the functions added to a filter hook.
apply_filters_ref_array() Execute functions hooked on a specific filter hook, specifying arguments in an array.
apply_filters_deprecated() Fires functions attached to a deprecated filter hook.
add_filter() Attaches the specified PHP function to the specified filter hook. Thus, when the filter is triggered, the value will be filtered by the specified PHP function.
remove_filter() Removes a function from a specified filter hook.
remove_all_filters() Remove all of the hooks from a filter.
current_filter() Retrieve the name of the current filter or action.
has_filter() Check if any filter has been registered for a hook.
doing_filter() Retrieve the name of a filter currently being processed.

Auxiliary WordPress functions for filters

WordPress has special functions that simplify working with filters.

Function Description
__return_true() Simply returns true. Helper function of WordPress.
__return_false() Simply returns false. Helper function of WordPress.
__return_zero() Simply returns 0. Helper function of WordPress. Useful for use in filters.
__return_empty_string() Simply returns an empty string:". Helper function of WordPress.
__return_empty_array() Simply returns an empty array: array(). Helper function of WordPress.
__return_null() Simply returns null. Auxiliary function of WordPress.

For example, we can disable all default WordPress widgets using the load_default_widgets filter, like this:

function is_load_default_widgets(){
	return false;
add_filter( 'load_default_widgets', 'is_load_default_widgets' );

Or you can use a ready-made function from the WordPress core instead of creating a separate function that returns false: __return_false():

add_filter( 'load_default_widgets', '__return_false' );

To understand how this works, let's look at the call of the load_default_widgets filter:

function wp_maybe_load_widgets(){

	if ( ! apply_filters( 'load_default_widgets', true ) )

	require_once( ABSPATH . WPINC . '/default-widgets.php' );

	add_action( '_admin_menu', 'wp_widgets_add_menu' );

When the wp_maybe_load_widgets() function is called, the filter is triggered. By default, it always returns true, and the condition is not met – the widgets are loaded. In the examples above, we return false, and the condition is met – the widgets are not loaded.

This is a demo example from the WordPress code to explain the principle of operation. It is better not to use it in practice. To disable widgets, use the code from the description of the unregister_widget() function.

Similar example

Similarly, you can disable the ability to publish posts via the xmlrpc protocol, which is actually enabled by default, but few people use it.

// disable publishing via xmlrpc
add_filter( 'xmlrpc_enabled', '__return_false' );

Another example

We can also disable the password reset feature using the allow_password_reset filter:

add_filter( 'allow_password_reset', '__return_false' );

Now, all users will not be able to reset passwords on the site.

List of all WordPress hooks

Getting a list of all hooks may be necessary during development or when debugging.

As mentioned earlier, all hooks are recorded in a single array, or more precisely in the global variable $wp_filters. By the way, if you delete an element of the array (hook) from $wp_filters, the hook will stop working...

The following code will display a list of all hooks (filters and events) registered at the time this code is called:

 * Displays a list of all WordPress hooks and the functions attached to them.
 * @param string $hook_name  The name of the hook for which the list of functions should be displayed.
 * @version 3.0
function get_hooks_list( string $hook_name = '' ): string {
	global $wp_filter;

	$wp_hooks = $wp_filter;

	// for version 4.4 - convert to array
	if( is_object( reset( $wp_hooks ) ) ){
		foreach( $wp_hooks as & $object ){
			$object = $object->callbacks;
		unset( $object );

	$hooks = [];

	if( $hook_name ){
		$hooks[ $hook_name ] = $wp_hooks[ $hook_name ] ?? null;

		if( ! is_array( $hooks[ $hook_name ] ) ){
			return "Nothing found for the '$hook_name' hook";
		$hooks = $wp_hooks;
		ksort( $wp_hooks );

	$output = '';
	foreach( $hooks as $name => $hook_data ){
		ksort( $hook_data );

		$output .= "\nHook\t<b>$name</b>\n";

		foreach( $hook_data as $priority => $hooksdata ){
			$output .= $priority;

			foreach( $hooksdata as $key => $hdata ){
				$func = $hdata['function'];

				if( is_array( $func ) ){

					if( is_object( $func[0] ) ){
						$func_name = get_class( $func[0] ) . '->' . $func[1];
					else {
						$func_name = $func[0] . '::' . $func[1];
				elseif( $func instanceof Closure ){
					$func_name = "Closure_$key";
				else {
					$func_name = $key;

				$output .= "\t$func_name()\n";

	return sprintf( '<%1$s>%2$s</%1$s>', 'pre', $output );

Example of usage:

echo get_hooks_list();

/* It will display something like this:

Hook wp_enqueue_scripts
10  lambda_2
99  theme_scripts_styles

Hook wp_footer
0   0000000072b7ec0d00002b862c2211a0enqueue_jquery_if_need
10  0000000072b7edb400002b862c2211a0footer_scripts
20  wp_print_footer_scripts
99  0000000072b7ec0d00002b862c2211a0add_script_to_footer
999 0000000072b7edb600002b862c2211a0footer_script
1000    wp_admin_bar_render
9999999999  0000000072b7eb0b00002b862c208180

... and so on ...

And this is how an element of the array looks in the $wp_filter variable:

global $wp_filter;

print_r( $wp_filter );

	[wp_title] => WP_Hook Object
			[callbacks] => Array
					[10] => Array
							[wptexturize] => Array
									[function] => wptexturize
									[accepted_args] => 1

							[convert_chars] => Array
									[function] => convert_chars
									[accepted_args] => 1

							[esc_html] => Array
									[function] => esc_html
									[accepted_args] => 1


					[11] => Array
							[capital_P_dangit] => Array
									[function] => capital_P_dangit
									[accepted_args] => 1



			[iterations:WP_Hook:private] => Array

			[current_priority:WP_Hook:private] => Array

			[nesting_level:WP_Hook:private] => 0
			[doing_action:WP_Hook:private] =>

	[widget_title] => WP_Hook Object
		............... and so on ...

How to get functions attached to a specific hook?

It is often necessary to see which functions are attached to a specific filter or event.

The above code will allow you to do this by specifying the $hook_name parameter:

echo get_hooks_list( 'the_title' );

/* It will display:

Hook    the_title
10  wptexturize
11  capital_P_dangit


Another way is to simply get the array data.

We use the global variable $wp_filters. It contains the data of all hooks.

Data in $wp_filters is added as the code is processed, so when using the variable $wp_filters, it matters when it is used: for example, if you use it at the beginning of the theme's functions.php file, it will contain all the hook functions added before this file is included, but it will not contain those added in this file or later.

 * Displays a list of functions/methods attached to the specified hook
 * @param (str) $hook The name of the hook for which the functions should be displayed.
function print_filters_for( $hook ){
	global $wp_filter;

	$data = isset( $wp_filter[$hook] ) ? $wp_filter[$hook] : "Hook `$hook` not found...";

	echo '<pre>', print_r( $data, 1 ) .'</pre>';

Now, to display a list of all functions/methods attached to a filter or event, you need to call this function and specify the hook name.

For example, let's get all the functions attached to the wp_footer event. In the callbacks index, we will get all the functions attached to the hook, in the order of their priority.

print_filters_for( 'wp_footer' );

/* It will display:

WP_Hook Object (

	[callbacks] => Array (

		[0] => Array (
			[echo_ads_tpls] => Array (
				[function] => echo_ads_tpls
				[accepted_args] => 1

		[20] => Array (
			[wp_print_footer_scripts] => Array (
				[function] => wp_print_footer_scripts
				[accepted_args] => 1

		[99] => Array (
			[question_close_ajax_js] => Array (
				[function] => question_close_ajax_js
				[accepted_args] => 1

			[add_question_rating_ajax_js] => Array (
				[function] => add_question_rating_ajax_js
				[accepted_args] => 1

		[1000] => Array (
			[wp_admin_bar_render] => Array (
				[function] => wp_admin_bar_render
				[accepted_args] => 1

	[iterations:WP_Hook:private] => Array()
	[current_priority:WP_Hook:private] => Array()
	[nesting_level:WP_Hook:private] => 0
	[doing_action:WP_Hook:private] =>


Dynamic hooks naming

In the WordPress documentation, there is an interesting note about naming dynamic hooks.

Use curly braces for variables in the name of dynamic hooks:

// Correct:
do_action( "{$new_status}_{$post->post_type}", $post->ID, $post );

// Incorrect:
do_action( $new_status . '_' . $post->post_type, $post->ID, $post );

This is necessary to simplify code analysis, for quick searching in the code editor, for convenient generation of hook documentation, etc.

Comments for dynamic hook (PHPDoc)

Also, in PHP comments for dynamic hooks, it is recommended to write possible variations of the specific hook name. The format of such a record looks like this:

 * Fires before a specified login form action.
 * Possible hook names include:
 *  - `login_form_checkemail`
 *  - `login_form_confirm_admin_email`
 *  - `login_form_confirmaction`
 *  - `login_form_entered_recovery_mode`
 *  - `login_form_login`
 *  - `login_form_logout`
 *  - `login_form_lostpassword`
 *  - `login_form_postpass`
 *  - `login_form_register`
 *  - `login_form_resetpass`
 *  - `login_form_retrievepassword`
 *  - `login_form_rp`
 * @since 2.8.0
do_action( "login_form_{$action}" );