Debug WordPress hooks

These functions are a little dated. I suggest to use better maintained R_Debug class instead.

Hooks is very important WordPress concept that allows to attach multiple functions that do something (actions) or modify data (filters) at specific points (hooks). Great deal of core and third party code uses hooks and since most of this stuff is going kinda under surface it can be hard to make sense of what is going on.

list_hooked_functions() is another of my WordPress beasts lost in the wild. Since then I dedicated some time to build a set of debug functions for WordPress hooks.

Hooks storage

Hooks are stored in global variable $wp_filter. You can simply display it as any variable, but it is large and complex array. What this set of function does is mostly making sense of that array and presenting data in clean readable form.

Show hook details

There are three things that can be hooked:

  • functions;
  • static class methods;
  • object methods.

First function deals with interpreting and formatting single hook, not really meant to be called directly.

function dump_hook( $tag, $hook ) {

    echo ">>>>>\t<strong>$tag</strong><br>";

    foreach( $hook as $priority => $functions ) {

	echo $priority;

	foreach( $functions as $function )
	    if( $function['function'] != 'list_hook_details' ) {

		echo "\t";

		if( is_string( $function['function'] ) )
		    echo $function['function'];

		elseif( is_string( $function['function'][0] ) )
		     echo $function['function'][0] . ' -> ' . $function['function'][1];

		elseif( is_object( $function['function'][0] ) )
		    echo "(object) " . get_class( $function['function'][0] ) . ' -> ' . $function['function'][1];


		echo ' (' . $function['accepted_args'] . ') <br>';

    echo '';

It will determine hooked stuff, sort it by priority and output.

Hooks map

Now that messy part is covered it is easy to see a list of all hooks and their content.

function list_hooks( $filter = false ){
	global $wp_filter;

	$hooks = $wp_filter;
	ksort( $hooks );

	foreach( $hooks as $tag => $hook )
	    if ( false === $filter || false !== strpos( $tag, $filter ) )
			dump_hook($tag, $hook);

When called this function will output current state of all hooks in alphabetized order. If passed string as argument it will only list hooks that have that string in name.

Makes it easy to get snapshot of everything or specific hook(s).

Hooks in real time

The one issue with listing current state of hooks is that it is not guaranteed to stay that way. Hooks are modified all the time, it is not uncommon for functions to be added and removed repeatedly.

How to see hook right when it is getting executed? We can add function to it that will output details of current hook.

function list_hook_details( $input = NULL ) {
    global $wp_filter;

    $tag = current_filter();
    if( isset( $wp_filter[$tag] ) )
		dump_hook( $tag, $wp_filter[$tag] );

	return $input;

Whenever hook with this function added gets executed it will output details right in place.

It is inconvenient to add this manually. Luckily there is special hook all that gets function executed in all hooks. Can hook live function there.

function list_live_hooks( $hook = false ) {
    if ( false === $hook )
		$hook = 'all';

    add_action( $hook, 'list_hook_details', -1 );

This will list live details on all hooks or specific hook, passed as argument.

Include and usage

These functions go in functions.php of theme, I just keep them in separate file and include conditionally when needed.

Also remember the difference in usage:

  • list_hooks() can be used anywhere (right now kind of a thing);
  • list_live_hooks() must be initiated early (schedule ahead kind of a thing).

And naturally these are strictly debug functions, I advise to use them on test sites only and limit output to logged in administrators otherwise. Especially live function – it can easily tear blog output apart.


I hope this would be of use, they saved me a lot of time and continue to do so. Suggestions of any changes or improvements are welcomed.

Related Posts


  • wp_insert_post_data Help #

    [...] posted my set of debug functions for WP hooks earlier this week https://www.rarst.net/script/debug-wordpress-hooks/ I keep finding rough spots after post went live (typical), but mostly they work fine. :) [...]
  • Debugging WordPress Roundup | Themergency #

    [...] Debug WordPress hooks – by Andrey Savchenko [...]
  • az #

    i am a wordpress beginner. where should i call list_live_hooks this from?
  • az #

    @az oh it is working. never mind. thank you.
  • Rarst #

    @az Ok, if you say so. :) And you are welcome. General update - I had tweaked this functions a lot recently, but as part of larger more complex class and it's not quite ready to replace this version.
  • Kavin #

    Thank you sir, this saved a lot of time.
  • When your wordpress post content goes missing! | Capability #

    [...] the_content() hook here. To trace the culprit, I decided to use one fantastic snippet written by Rarst, that outputs the list of all hooks and respective filters attached to [...]
  • Sergio Garcia #

    Solid work with these functions. Thanks for making them available.
  • Noyb #

    Seeing not a single date on the entire page ... I have no idea if this was developed yesterday or 6 years ago. It's easier to go somewhere else .. and never come back.
  • Rarst #

    @Noyb Which stands for "None Of Your Business" I assume? Rude and lame. 1. The post explicitly has date at the end when I last applied revision to code. 2. If you don't care to spend two minutes (many less then it took me to bring this code from idea to implementation and this post) to test if code is still working - I don't care what is easier for you. 3. Go. You won't be missed.
  • Phil #

    Very nice plugin. I've just started developing with Wordpress so I am learning everything as I go and this is really helpful for a visual thinker like myself. Cheers
  • How to do damn near anything with WordPress &ndash; Stephanie Leary #

    [...] List all hooked functions [...]