How do filters and hooks really work in PHP

How does filters and hooks actually work in WordPress?

I’m asking about something advanced. How is it implemented in PHP? E.g how does it collect all the hooks from the different plugins and “attach” them to the core hooks etc.



Basically the “Plugin API,” which summons Filters and Hooks, consists out of the following functions:

  1. apply_filters()execute
  2. do_actionexecute
  3. apply_filters_ref_array()execute
  4. do_action_ref_array()execute
  5. add_filter()add to stack
  6. add_action()add to stack

Basic Internals

Overall there’re a couple of globals (what else in WordPress world) involved:

global $wp_filter, $wp_actions, $wp_current_filter, $merged_filters;

The first one $wp_filter is a global Array that holds all filter names as subarrays. Each of those subarrays then holds even more subarrays that are callbacks summoned under a priority array.

Brief in-depth

So when an execute function is called, WordPress searches those globals arrays for the keys with that name. Then the attached callbacks get executed priority after priority. The only thing that happens up front are callbacks attached to the all filter.

When you add a callback using add_action or add_filter, then WordPress first calculates a “unique” ID to not overwrite already attached callbacks.

$idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);

Then it adds your callback to the global $wp_filter stack:

$wp_filter[ $tag ][ $priority ][ $idx ] = array(
    'function'      => $function_to_add,
    'accepted_args' => $accepted_args

As you can see the main sub array is the $tag (or action/filter name), then everything is summoned under a specific priority, and then the “unique” callback/ID string gets used as key.

Later, when a filter gets called – happening with the $tag/action-/filter-name – the array gets searched and the callbacks get called. As it is using call_user_func_array it doesn’t really matter how many arguments are attached. WordPress resolves that by itself.

foreach ( (array) current( $wp_filter[ $tag ] ) as $the_ )
            (int) $the_['accepted_args']

Leave a Comment