Hooks API

The foundation of WordPress extensibility. Hooks allow plugins and themes to modify behavior without editing core files.

Since: 0.71 (filters), 1.2.0 (actions)
Source: wp-includes/plugin.php, wp-includes/class-wp-hook.php

Components

Component Description
functions.md Core hook registration and execution functions
class-wp-hook.md Internal hook implementation class
common-hooks.md Categorized list of common hooks

Architecture

WordPress hooks come in two types:

  • Actions — Execute code at specific points (fire-and-forget)
  • Filters — Modify and return data (value transformation)

Both use the same underlying WP_Hook class. Actions are implemented as filters that ignore return values.

Global State

$wp_filter          WP_Hook[]   All registered hooks (keyed by hook name)
$wp_actions         int[]       Action execution counts (keyed by hook name)
$wp_filters         int[]       Filter execution counts (keyed by hook name)  
$wp_current_filter  string[]    Stack of currently executing hooks

Registration Flow

add_action() / add_filter()
    └── $wp_filter[ $hook_name ] = new WP_Hook()  (if not exists)
            └── WP_Hook::add_filter()
                    └── _wp_filter_build_unique_id()  (callback key)
                            └── Store in $this->callbacks[ $priority ][ $id ]

Execution Flow

Filters

apply_filters( $hook_name, $value, ...$args )
    ├── ++$wp_filters[ $hook_name ]
    ├── _wp_call_all_hook()  (if 'all' hook exists)
    ├── $wp_current_filter[] = $hook_name
    ├── WP_Hook::apply_filters( $value, $args )
    │       └── foreach priority → foreach callback
    │               └── call_user_func_array() → $value
    ├── array_pop( $wp_current_filter )
    └── return $value

Actions

do_action( $hook_name, ...$args )
    ├── ++$wp_actions[ $hook_name ]
    ├── _wp_call_all_hook()  (if 'all' hook exists)
    ├── $wp_current_filter[] = $hook_name
    ├── WP_Hook::do_action( $args )
    │       └── $this->doing_action = true
    │       └── apply_filters( '', $args )  (value ignored)
    └── array_pop( $wp_current_filter )

Priority System

Callbacks execute in priority order (lower = earlier). Same-priority callbacks execute in registration order.

Priority Use Case
1-4 Must run first (setup, early modification)
5-9 Run early
10 Default
11-19 Run late
20+ Must run last (cleanup, final modification)
PHP_INT_MAX Absolute last

Callback Identification

_wp_filter_build_unique_id() generates unique keys for callbacks:

Callback Type Key Format
Function name "function_name"
Static method "Class::method"
Object method spl_object_hash($obj) . "method"
Closure spl_object_hash($closure) . ""

Nesting & Recursion

The hook system supports:

  • Nested hooks — Firing a hook from within a hook callback
  • Recursive hooks — Same hook firing multiple times (tracked via $nesting_level)
  • Dynamic modification — Adding/removing callbacks during execution

WP_Hook maintains iteration state per nesting level to handle mid-execution modifications safely.

The ‘all’ Hook

Special hook that fires for every action and filter:

add_action( 'all', function( $hook_name ) {
    error_log( 'Hook fired: ' . $hook_name );
} );

Receives the hook name plus all arguments. Useful for debugging. Performance-intensive.