WordPress Bootstrap Hooks
Hooks fired during WordPress initialization and request handling, in execution order.
Early Bootstrap Hooks
These hooks fire before plugins load. They can only be used by mu-plugins or by pre-defining filters in wp-config.php.
enable_maintenance_mode
Filter whether to enable maintenance mode.
apply_filters( 'enable_maintenance_mode', bool $enable, int $upgrading ): bool
Parameters:
$enable– Whether to enable maintenance mode (defaulttrue)$upgrading– Timestamp from.maintenancefile
Since: 4.6.0
enable_wp_debug_mode_checks
Filter whether to apply debug mode settings.
apply_filters( 'enable_wp_debug_mode_checks', bool $enable ): bool
Default: true
Usage: Define filter in wp-config.php before loading WordPress:
$GLOBALS['wp_filter'] = array(
'enable_wp_debug_mode_checks' => array(
10 => array(
array(
'accepted_args' => 0,
'function' => function() { return false; },
),
),
),
);
Since: 4.6.0
enable_loading_object_cache_dropin
Filter whether to load object-cache.php drop-in.
apply_filters( 'enable_loading_object_cache_dropin', bool $enable ): bool
Default: true
Since: 5.8.0
Plugin Loading Hooks
muplugins_loaded
Action fired after must-use plugins load.
do_action( 'muplugins_loaded' );
When: After mu-plugins are loaded, before regular plugins
Since: 2.8.0
plugins_loaded
Action fired after all plugins load.
do_action( 'plugins_loaded' );
Common Uses:
- Initialize plugin functionality
- Register custom post types (though
initis preferred) - Load plugin textdomains
- Check for plugin dependencies
Since: 1.5.0
Theme Loading Hooks
setup_theme
Action fired before theme is loaded.
do_action( 'setup_theme' );
When: After plugins loaded, before theme’s functions.php
Common Uses:
- Register theme support features
- Initialize theme-related functionality early
Since: 3.0.0
after_setup_theme
Action fired after theme’s functions.php loads.
do_action( 'after_setup_theme' );
Common Uses:
add_theme_support()- Register nav menus
- Set content width
- Load theme textdomain
Example:
add_action( 'after_setup_theme', function() {
add_theme_support( 'post-thumbnails' );
add_theme_support( 'title-tag' );
register_nav_menus( array(
'primary' => 'Primary Menu',
) );
} );
Since: 3.0.0
Initialization Hooks
init
Action fired after WordPress is fully loaded.
do_action( 'init' );
The most important hook. WordPress core, plugins, and themes are all loaded.
Common Uses:
- Register post types and taxonomies
- Register shortcodes
- Initialize sessions
- Start output buffering
- Any initialization that requires full WordPress
Example:
add_action( 'init', function() {
register_post_type( 'book', array(
'public' => true,
'label' => 'Books',
) );
} );
Since: 1.0.0
wp_loaded
Action fired after WordPress and all plugins/themes are fully loaded.
do_action( 'wp_loaded' );
When: After init, before request parsing
Common Uses:
- Buffer flushing
- Late initialization
- Actions that must run after all
inithooks
Since: 3.0.0
Request Parsing Hooks
do_parse_request
Filter to short-circuit request parsing.
apply_filters( 'do_parse_request', bool $parse, WP $wp, string|array $extra_query_vars ): bool
Return: false to prevent default parsing
Use Case: Custom routing, headless setups
Since: 3.5.0
query_vars
Filter allowed public query variables.
apply_filters( 'query_vars', array $public_query_vars ): array
Example:
add_filter( 'query_vars', function( $vars ) {
$vars[] = 'my_custom_var';
return $vars;
} );
Since: 1.5.0
request
Filter the parsed query variables.
apply_filters( 'request', array $query_vars ): array
Example:
add_filter( 'request', function( $query_vars ) {
if ( isset( $query_vars['my_custom_var'] ) ) {
$query_vars['post_type'] = 'custom';
}
return $query_vars;
} );
Since: 2.1.0
parse_request
Action fired after request variables are parsed.
do_action_ref_array( 'parse_request', array( WP &$wp ) );
Access: $wp->query_vars, $wp->matched_rule, $wp->request
Since: 2.1.0
Headers Hooks
wp_headers
Filter HTTP headers before sending.
apply_filters( 'wp_headers', array $headers, WP $wp ): array
Example:
add_filter( 'wp_headers', function( $headers ) {
$headers['X-Custom-Header'] = 'value';
return $headers;
} );
Since: 2.8.0
send_headers
Action fired after headers are sent.
do_action_ref_array( 'send_headers', array( WP &$wp ) );
Since: 2.1.0
404 Handling
pre_handle_404
Filter to short-circuit 404 handling.
apply_filters( 'pre_handle_404', bool $preempt, WP_Query $wp_query ): bool
Return: Non-false to skip default 404 handling
Since: 4.5.0
Main Query Hook
wp
Action fired after WordPress environment is set up.
do_action_ref_array( 'wp', array( WP &$wp ) );
The query is complete. Posts are loaded, conditional tags work.
Common Uses:
- Redirect logic
- Access control checks
- Modify global post data
Example:
add_action( 'wp', function( $wp ) {
if ( is_singular( 'premium' ) && ! current_user_can( 'read_premium' ) ) {
wp_redirect( home_url( '/subscribe/' ) );
exit;
}
} );
Since: 2.1.0
Template Hooks
template_redirect
Action fired before template loads.
do_action( 'template_redirect' );
Common Uses:
- Redirects
- Output buffering
- Header modifications
- Access control
Since: 1.5.0
Shutdown Hooks
shutdown
Action fired when PHP shuts down.
do_action( 'shutdown' );
When: Registered via register_shutdown_function()
Common Uses:
- Cleanup operations
- Logging
- Cache operations
Since: 1.2.0
Default Filters (default-filters.php)
This file registers core filter and action callbacks. Key registrations:
Content Filters
// The Content
add_filter( 'the_content', 'do_blocks', 9 );
add_filter( 'the_content', 'wptexturize' );
add_filter( 'the_content', 'convert_smilies', 20 );
add_filter( 'the_content', 'wpautop' );
add_filter( 'the_content', 'shortcode_unautop' );
add_filter( 'the_content', 'do_shortcode', 11 );
add_filter( 'the_content', 'wp_filter_content_tags', 12 );
Title Filters
add_filter( 'the_title', 'wptexturize' );
add_filter( 'the_title', 'convert_chars' );
add_filter( 'the_title', 'trim' );
Excerpt Filters
add_filter( 'the_excerpt', 'wptexturize' );
add_filter( 'the_excerpt', 'convert_smilies' );
add_filter( 'the_excerpt', 'convert_chars' );
add_filter( 'the_excerpt', 'wpautop' );
add_filter( 'get_the_excerpt', 'wp_trim_excerpt', 10, 2 );
Head Actions
add_action( 'wp_head', '_wp_render_title_tag', 1 );
add_action( 'wp_head', 'wp_enqueue_scripts', 1 );
add_action( 'wp_head', 'wp_resource_hints', 2 );
add_action( 'wp_head', 'feed_links', 2 );
add_action( 'wp_head', 'feed_links_extra', 3 );
add_action( 'wp_head', 'wp_robots', 1 );
add_action( 'wp_head', 'wp_print_styles', 8 );
add_action( 'wp_head', 'wp_print_head_scripts', 9 );
add_action( 'wp_head', 'wp_generator' );
add_action( 'wp_head', 'rel_canonical' );
add_action( 'wp_head', 'wp_site_icon', 99 );
Footer Actions
add_action( 'wp_footer', 'wp_print_footer_scripts', 20 );
REST API Actions
add_action( 'init', 'rest_api_init' );
add_action( 'rest_api_init', 'rest_api_default_filters', 10, 1 );
add_action( 'rest_api_init', 'register_initial_settings', 10 );
add_action( 'rest_api_init', 'create_initial_rest_routes', 99 );
add_action( 'parse_request', 'rest_api_loaded' );
Authentication Filters
add_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
add_filter( 'authenticate', 'wp_authenticate_email_password', 20, 3 );
add_filter( 'authenticate', 'wp_authenticate_application_password', 20, 3 );
add_filter( 'authenticate', 'wp_authenticate_spam_check', 99 );
add_filter( 'determine_current_user', 'wp_validate_auth_cookie' );
add_filter( 'determine_current_user', 'wp_validate_logged_in_cookie', 20 );
Cron Actions
add_action( 'init', 'wp_cron' ); // Only if not DOING_CRON
Widget Actions
add_action( 'plugins_loaded', 'wp_maybe_load_widgets', 0 );
add_action( 'init', 'wp_widgets_init', 1 );
Theme Actions
add_action( 'setup_theme', 'create_initial_theme_features', 0 );
add_action( 'after_setup_theme', '_add_default_theme_supports', 1 );
Post Type/Taxonomy Actions
add_action( 'init', 'create_initial_post_types', 0 );
add_action( 'init', 'create_initial_taxonomies', 0 );
Hook Execution Order Summary
enable_maintenance_mode(filter)enable_wp_debug_mode_checks(filter)enable_loading_object_cache_dropin(filter)- mu-plugins loaded
muplugins_loaded(action)- plugins loaded
plugins_loaded(action)setup_theme(action)- theme functions.php loaded
after_setup_theme(action)init(action)wp_loaded(action)do_parse_request(filter)query_vars(filter)request(filter)parse_request(action)- WP_Query executed
pre_handle_404(filter)wp_headers(filter)send_headers(action)wp(action)template_redirect(action)- template loaded
shutdown(action)
Protected AJAX Actions
These AJAX actions are protected in recovery mode:
$actions_to_protect = array(
'edit-theme-plugin-file',
'heartbeat',
'install-plugin',
'install-theme',
'search-plugins',
'search-install-plugins',
'update-plugin',
'update-theme',
'activate-plugin',
);
Filter: wp_protected_ajax_actions
Request Type Filters
wp_doing_ajax
apply_filters( 'wp_doing_ajax', bool $is_ajax ): bool
wp_doing_cron
apply_filters( 'wp_doing_cron', bool $is_cron ): bool
wp_using_themes
apply_filters( 'wp_using_themes', bool $use_themes ): bool
Filter/Action Best Practices
Priority Guidelines
- 0-5: Core functionality, must run first
- 10: Default priority
- 11-15: After core filters (e.g., do_shortcode at 11)
- 20+: Late execution
- 100+: Final modifications
Common Patterns
// Add custom query var
add_filter( 'query_vars', function( $vars ) {
$vars[] = 'my_var';
return $vars;
} );
// Modify request
add_filter( 'request', function( $vars ) {
if ( isset( $vars['my_var'] ) ) {
// Modify query based on custom var
}
return $vars;
} );
// Late init
add_action( 'wp_loaded', function() {
// Runs after all init hooks
}, 10 );
// Before template
add_action( 'template_redirect', function() {
if ( some_condition() ) {
include get_template_directory() . '/custom-template.php';
exit;
}
} );
// Modify headers
add_filter( 'wp_headers', function( $headers ) {
$headers['X-Frame-Options'] = 'SAMEORIGIN';
return $headers;
} );