Tips for Working With WordPress Actions and Filters

WordPress plugins and themes are often customizable with functions called “hooks”. There are two types of hooks: actions and filters.

If you’re not familiar with actions and filters, then definitely spend some time learning the basics. The WordPress Codex has an in-depth introduction to them here, and Treehouse has a great overview here, for example.

Once you’ve learned the basics of how to use actions and filters, it’s time to learn some tricks to help you get the most out of them.

In this Post


Finding Actions and Filters

So you’re convinced of the value of actions and filters, and are ready to start using them in your custom code—excellent!

But where are all of these actions and filters in the first place? Many plugins and themes have dozens and dozens of these hooks, especially large plugins like The Events Calendar, Event Tickets, Easy Digital Downloads, WooCommerce, etc.

Some plugins, like WooCommerce, have complete “Hook References” that list all of the plugin’s hooks. If the plugin you’re customizing has this sort of documentation, use it—look for filters and actions in the official online documentation and use any example code that might be provided.

Far more plugins and themes out there don’t have the sort of comprehensive documentation that WooCommerce has, though. If you’re working with one of these pieces of software, then you’ll have to be a bit clever with how you find actions and filters.

  • First, you’ll need a code editor that has a “Find in Folder” feature. The vast majority of editors have this feature or something similar to it. Learn the specific mode of searching within folders with your editor of choice. (You can grep within directories from the command line, too.)

    I personally use Sublime Text, which has a very convenient “Find in Folder” option whenever you right-click on a directory, as shown in the following screenshot.

    The "Find in Folder" Feature in Sublime Text

    An example of the conveniently-placed “Find in Folder” feature in Sublime Text.

  • Next, navigate to the directory for the plugin or theme whose hooks you are trying to explore. In this example, as seen in the screenshot above, I’ll be searching for actions and filters within The Events Calendar.
  • After navigating to the directory in which you’ll be searching, use the “Find in Folder” feature and search for do_action to find actions, or apply_filters to find filters. In Sublime Text, for example, here’s what that looks like:

    Searching for Actions in Sublime Text

    Searching for all instances of do_action within The Events Calendar with Sublime Text.

Doing all of the above steps will reveal a “results” page within your code editor of all instances of do_action or apply_filters, depending on which one you searched for.

This results page is essentially the most comprehensive “hook reference” you could ever get—it will reveal each hook exactly where it is used. Here is an example results page for actions within The Events Calendar after searching in Sublime Text:

A Search Results Page in Sublime Text

A search results page in Sublime Text, revealing instances of the do_action call within The Events Calendar.

I personally always use this method to find filters and actions, even for plugins or themes with great online documentation. With this method, you don’t find the hooks on a web page and hope that the documentation is up-to-date and accurate—you find the hooks right within the actual code, so you get the whole context in which the hooks are used, and can be certain that what you’re looking at is up-to-date and accurate.


Using Arguments in Callback Functions

Most actions and filters are pretty simple in terms of their construction. They’ll often be written like this, for example:

$to = apply_filters( 'tribe_rsvp_email_recipient', $to );

In this example, you have only two things to consider: the name of the filter, and the value that is being filtered. That’s all! So your callback function would be commensurately simple: you would attach your callback function to the name of the filter with add_filter(), and then modify the value in the callback function.

The above filter is from Event Tickets, and allows you to filter the “to” address for RSVP emails. So if you wanted to make all RSVP confirmation emails go to the email address ticket-tracker@example.com, you would write a custom snippet of code like this:

function tribe_blog_example_callback( $to ) {
    $to = 'ticket-tracker@example.com';
    return $to;
}

add_filter( 'tribe_rsvp_email_recipient', 'tribe_blog_example_callback' );

Some hooks are not as simple, though. You might come across more seemingly-complicated ones, like this other example from Event Tickets:

do_action( 'event_tickets_rsvp_attendee_created', $attendee_id, $event_id, $order_id );

While the tribe_rsvp_email_recipient filter shown above just allows you to modify an email address, this event_tickets_rsvp_attendee_created action allows for more complex modifications—it fires when a user makes an RSVP to an event, and allows you to hook into that event to do anything you’d like.

Notice how many arguments are passed here compared to the previous hook. The previous hook had just one argument, $to, but this hook has three:

  • $attendee_id
  • $event_id
  • $order_id

Let’s say you wanted to update a post meta field for an event any time someone made an RSVP to it. To do this, you need the event’s ID. You might see that $event_id is an argument for the hook and think, “Great! I can just use that $event_id argument instead of having to manually find the event’s ID on my own.” With this in mind, you write out your callback function like this:

function tribe_blog_example_rsvp_callback( $attendee_id, $event_id ) {
    update_post_meta( $event_id, '_example_meta_field', absint( $attendee_id ) );
}

add_action( 'event_tickets_rsvp_attendee_created', 'tribe_blog_example_rsvp_callback' );

But wait! If you do this, you will get an error.

In the callback function, tribe_blog_example_rsvp_callback, you are using two arguments. But in the add_action call, that fact is not declared:

add_action( 'event_tickets_rsvp_attendee_created', 'tribe_blog_example_rsvp_callback' );

To be able to use two arguments—$attendee_id and $event_id in this example—you would need to modify the add_action call to declare that you are using two arguments. It would look something like this:

add_action( 'event_tickets_rsvp_attendee_created', 'tribe_blog_example_rsvp_callback', 10, 2 );

If you wanted to use all three arguments, then your add_action call would look like this:

add_action( 'event_tickets_rsvp_attendee_created', 'tribe_blog_example_rsvp_callback', 10, 3 );

You might be wondering, “what’s that 10 in these add_action calls?” This is just the “priority” value, which defaults to 10 in WordPress. This value defines the order in which hooks will run, starting with lower numbers first and working up from there.

You rarely need to modify this, but let’s say, for example, you wanted to ensure your callback function ran after all other callback functions on a specific hook. You can do this by setting the priority higher than the default 10. The vast majority of callback functions for hooks run on priority 10 or higher, so you can usually run after everything by simply setting the priority to 11. So your add_action call would look like this:

add_action( 'event_tickets_rsvp_attendee_created', 'tribe_blog_example_rsvp_callback', 11, 3 );

☝️ Let’s recap and review what this means. This add_action call is making the following declarations:

  • When the action event_tickets_rsvp_attendee_created fires, run the function tribe_blog_example_rsvp_callback.
  • The tribe_blog_example_rsvp_callback should run very late. Let all functions with priority 1 through 10 run before it, if they exist.
  • Let the tribe_blog_example_rsvp_callback function use all three arguments that the event_tickets_rsvp_attendee_created hook provides. In this example, those arguments are $attendee_id, $event_id, and $order_id.

Finding All Callbacks Attached to a Hook

Sometimes you need or want to see all of the functions that are attached to a given hook. This can provide insight when debugging code, for example, or when trying to identify the culprit in an odd support issue.

The simplest way to do this is to use code like the following, which is a snippet I picked up a couple of years ago from the user Rilwis on the WordPress StackExchange:

global $wp_filter;
print '<pre>';
print_r( $wp_filter['admin_bar_menu'] );
print '</pre>';

I often attach this code to the wp_footer or admin_footer actions, like this:

add_action( 'wp_footer', function() {
    global $wp_filter;
    print '<pre>';
    print_r( $wp_filter['admin_bar_menu'] );
    print '</pre>';
});

What this code will do is show a neatly formatted array of all of the functions attached to a particular hook. In the example code above, the hook being examined is the action admin_bar_menu. You can see an example of the output of this function in the following screenshot:

An Array of Callback Functions

An array of callback functions attached to the admin_bar_menu hook.

When is this useful? Well, if you’ve written a callback function that doesn’t seem to be working, you can use this method to manually double-check that the callback function is even properly attached to the action. Once you’ve confirmed it’s there, maybe you can identify functions that are running after your callback that might be undoing the thing your callback does—thus prompting you to change your callback’s priority and sigh with relief that things now work as expected.


The “hooks” system within WordPress, more formally referred to as the Plugin API, is one of the CMS’s primary selling points: it lets you modify the appearance and behavior of things extensively without having to modify the actual core code of WordPress, or of a given plugin or theme.

Whole ecosystems have been built on this Plugin API. When you see a plugin like WooCommerce that has a litany of feature-rich extensions, it’s the Plugin API that makes it possible for those extensions to exist.

If your job or interests are related to WordPress in any way, familiarizing yourself with the Plugins API is a worthy investment of your time and attention. If this article has done its job and made you curious to learn more, here are some other great articles on the topic: