DEV Community

Cover image for How to get started with WordPress Hooks in Javascript
David Woolf
David Woolf

Posted on • Updated on • Originally published at indexforwp.com

How to get started with WordPress Hooks in Javascript

WordPress has provided hooks in PHP for years and they recently released a version for Javascript. Hooks allow different parts of your code to augment values or perform additional actions. When referring to actions and filters, we'll be using the term "hooks" to discuss both. If you see the words "action" or "filter", assume we're discussing functionality that only relates to only that hook.

How to start using WordPress hooks in Javascript

Before handing WordPress hooks in Javascript, make sure you are coding in a JS file that has access to the global wp javascript variable, or that you are using the @wordpress/hooks npm package

This article will be using the wp global variables hook endpoints for coding examples. If you are enqueuing your javascript correctly in WordPress, you should already have access to this variable. You can confirm this by doing console.log(wp.hooks)

Adding your own hooks

Adding actions and filters in Javascript is similar to PHP:

// actions
wp.hooks.addAction('hookName', 'namespace', callback, priority)

// filters
wp.hooks.addFilter('hookName', 'namespace', callback, priority)
Enter fullscreen mode Exit fullscreen mode

The parameters for both hook types are:

  • hookName: the name of your action or filter, which you'll use to call the hook
  • namespace: a custom namespace (for example: your product name).
  • callback: the function that will execute your hook 
  • priority: the order in which your hook fires

I'm not sure why the namespace parameter exists because you don't use it when calling a hook (although you do when removing one). To prevent duplicate hook names, I would recommend adding a namespace to your hook name as well.

Applying hooks in your code

Just like with PHP, you have access to a couple of functions to call your filters and actions:

// actions
wp.hooks.doAction('hookName', ..args)

// filters
wp.hooks.applyFilters('hookName', 'content', ...args)
Enter fullscreen mode Exit fullscreen mode

Notice how we don't refer to the namespace here, which is why I recommend adding one to your hook name.

Reminder: filters take a default value before the args list, and should return a value to a variable. Actions should execute code and not return anything.

With these four API methods, you can implement a Javascript version of WordPress's hooks system.

Troubleshooting when hooks don't fire in the correct order

An issue I ran into the first time I tried to use the wp.hooks.addFilter method was inconsistent filter execution.

I was trying to pass a string through two addFilter calls in separate plugins and I wanted the end value to include any modifications in each callback. Here is how I enqueued my javascript files in PHP (split between two plugin.php files):

// first plugin
wp_enqueue_script(
    'ndx-first-plugin-script', 
    plugin_dir_url(__FILE__) . 'dist/js/first.js', 
    [], 
    '1.0.0', 
    true
);

// second plugin
wp_enqueue_script(
    'ndx-second-plugin-script',
     plugin_dir_url(__FILE__) . 'dist/js/second.js',
     [],
     '1.0.0',
     true
);
Enter fullscreen mode Exit fullscreen mode

In my first.js file I created a filter that would return "I am the beginning" prepended to a passed in value:

// ndx-first-plugin-script (first.js)
wp.hooks.addFilter(
    "ndx_change_string",
    "index",
    (value) => {
        return `I am the beginning. ${value}`
    },
    10
)
Enter fullscreen mode Exit fullscreen mode

In my second.js file, I added the same filter hook with a higher (read: lesser) priority and appended "I am the end" to the passed-in value:

// ndx-second-plugin-script (second.js)
wp.hooks.addFilter(
    "ndx_change_string",
    "index",
    (value) => {
        return `${value} I am the end.`
    },
    20
)

console.log(wp.hooks.applyFilters("ndx_change_string", ""))
Enter fullscreen mode Exit fullscreen mode

Because my apply calls passed in empty strings I expected the result: "I am the beginning. I am the end." but what I got was "I am the end."

Unfortunately, my second plugin's javascript loads first and doesn't see the first plugin's filter value (this can happen in PHP too, by the way). You will generally use filters to augment a standalone value, but it's also common to use them to add and remove items from arrays so sometimes the order is important.

There are a couple of ways to solve this problem:

Ensure the plugin where you plan to call applyFilters is enqueued as a dependency in your other scripts:

// second plugin
wp_enqueue_script(
    'ndx-second-plugin-script',
     plugin_dir_url(__FILE__) . 'dist/js/second.js',
    ['ndx-first-plugin-script'], // add your first plugin script as a required dependency
    '1.0.0',
    true
);
Enter fullscreen mode Exit fullscreen mode

Or utilize the built-in hookAdded method to call additional filters after the first one is created:

wp.hooks.addAction(
    "hookAdded",
    "core/i18n",
    (name, functionName, callback, priority) => {
        if(name == "ndx_change_string" && priority == 10) {
               // add additional filters here after the first one fires
        }
    },
    10
)
Enter fullscreen mode Exit fullscreen mode

Note that the hookAdded method can be fragile and buggy and it would be very easy to get stuck in an infinite loop if two addFilter calls had a priority of 10.

Top comments (0)