Heads Up! Originally, I wanted to include both how to identify anonymous functions in WordPress and how to unhook them; however, the more I began writing about the topic, the longer the article became.
So I’ve split the content into two articles: This one outlines how to identify anonymous functions registered with hooks. A future article will detail how to de-register said functions.
Previously, I explain how to identify and register anonymous functions in WordPress. As I wrote in the introduction:
As I started writing, it became obvious it’s helpful to understand what PHP does behind-the-scenes when anonymous functions are registered.
So during the first article, I spend time explaining both how anonymous functions are registered – which is clear enough – and how anonymous functions are managed internally by PHP.
If you haven’t read the article, I urge you to do so. But if you’re opting out, the short of it is this:
- You register an anonymous function with an associated WordPress hook,
- PHP generates an ID via hashing for the anonymous function so that it can be managed internally.
It sound easy enough, but problems arise if you want to programmatically identify those anonymous functions. PHP keeps track of them and the functions fire as they are intended but what happens if you, as a developer, want to access those functions to deregister them?
Identify Anonymous Functions
Before looking how, or if, it’s even possible to deregister anonymous functions, it’s important to know how to identify anonymous functions programmatically. That is, if we know we’re working in an environment where anonymous functions have been registered, how do we actually find them?
Again, since these functions are registered with WordPress hooks and since these functions have an ID internally generated by PHP, there’s code we can write to help us understand where these functions are registered.
In the following bit, I’ll show exactly how to do this. This won’t necessarily explain what the code is going nor will it explain who registered the code, but it’ll give us some insight as to what anonymous functions are registered with which hooks.
And that’s a good starting place.
Finding Anonymous Functions
Before using any other specific tools, I’m going to use the following:
- the IDE of my choice, Visual Studio Code,
- a local installation of WordPress,
- whatever theme the installation is using (which, at the time of this writing, is twentytwenty),
- and the
functions.php
of said theme.
It’s not pretty, this isn’t the usual set of tools with which I’d recommend using, but it’s a starting point that’s going to demonstrate the point. In other words, this is a quick and dirty approach to get started.
Further, we’ll be writing anonymous functions in the theme’s functions.php
to make it easier to have parity with the content of the article.
With all of that in place, I’ll open functions.php
and then add the following code:
add_action('wp_head', 'listRegisteredFunctions', PHP_INT_MAX); /** * Lists all the registered functions. * * @return void */ function listRegisteredFunctions() { global $wp_filter; echo << HTML; print_r($wp_filter); echo <<
HTML; }
This uses the global $wp_filter
object which holds information on all of the referenced actions and filters with WordPress. Note also that I’m setting this up to fire in the wp_head
hook and that I’m using PHP_INT_MAX
to make sure it has the highest priority (so it fires as late as possible).
If you run this and then refresh the homepage of your installation, you’re going to see a lot of information. Some of it will make sense, some of it may not. Regardless, it’s going to be a lot of data. And as interesting as it is, there’s not much we can do with it.
To help simplify what it renders, let’s look at something that’s registered with just one of the hooks. Specifically, let’s look and see what’s registered with the wp_enqueue_scripts
hook. This hook is one that most anyone who has worked with theme or plugin development has used and something that’s going to have a number of associated callbacks within the context of a theme.
Note, I’m going to use a similar function as used above. I will, however, be changing the actual code in the function. Additionally, note that I have some guard clauses defined for early return so that if nothing is registered with the hook or if there are no callbacks, the function won’t run.
The code looks like this:
add_action('wp_head', 'listRegisteredFunctions', PHP_INT_MAX); /** * Lists all the registered functions. * * @return void */ function listRegisteredFunctions() { global $wp_filter; if (!isset($wp_filter['wp_enqueue_scripts'])) { return; } // Get all functions/callbacks hooked to wp_enqueue_scripts $callbacks = $wp_filter['wp_enqueue_scripts']->callbacks; if (empty($callbacks)) { return; } // ... }
It’s not going to render anything yet, though, because I don’t have the code for actually rendering the callbacks and functions associated with the hook. To do that, we can iterate through the callbacks and get each function and its associated priority.
To render that, we need to add:
echo '
'; foreach ($callbacks as $priority => $functions) { foreach ($functions as $function) { print_r([$function, $function['function']]); echo '
'; } } echo '';
The two important things to take away from the above code are:
- I’m adding the
function
and the$function['function']
to an array that’s dumped byprint_r
.$function['function']
contains a reference to the callback function.In the outer
foreach
loop, note that$functions
is the associative array representing the callbacks hooked to thewp_enqueue_scripts
. In the inner loop,$function
has information about the callback and$function['function']
is the actual callback itself.In the environment I’m using to test this code, I’m running the twentytwenty theme and I’ve added the above code to
functions.php
. If you’re following along with the same – even if it’s a different theme – you’ll likely see something like this written out to the screen:Array ( [0] => Array ( [function] => twentytwenty_register_scripts [accepted_args] => 1 ) [1] => twentytwenty_register_scripts )
I’ve opted to use this as an example because it’s prefixed with
twentytwenty_
meaning it’s likely going to be found within the theme. And when I search for this function in the theme within my IDE, I found the following:/** * Register and Enqueue Scripts. * * @since Twenty Twenty 1.0 */ function twentytwenty_register_scripts() { // Code remove to keep the code succinct. } add_action( 'wp_enqueue_scripts', 'twentytwenty_register_scripts' );
The important thing to note here is that we see the function
twentytwenty_register_scripts
is, in fact, registered with thewp_enqueue_scripts
hook.The purpose of looking at this is to see that we’re successfully able to find code that’s registered with our hook of choice. The next challenge, though, is finding anonymous functions that are registered with the same hook.
You can argue that it’d be more helpful to go ahead and find all anonymous functions registered with this hook but let’s first create out own so we can get an idea as to how this looks.
When doing this, you’ll see how complex, though not impossible, managing anonymous functions can be.
Creating Our Own Anonymous Function
First, comment out the code that’s listing all of the functions registered with the
wp_enqueue_scripts
hook.Next, let’s add our own anonymous functions to
functions.php
. This will render a message at the top of the page and it will allow us to use previously written code to track track this anonymous function.add_action('wp_enqueue_scripts', function () { echo << This is a a sample anonymous function.