Go back WordPress Request Lifecycle & Hooks /* by Maulik Macwan - February 17, 2026 */ Tech Update Introduction Understanding WordPress hooks and request lifecycle is one of the most valuable skills a WordPress developer can have. Every time a user visits a WordPress page, a detailed sequence of events fires behind the scenes — and WordPress hooks let you tap into that sequence at precisely the right moment. This post is your reference map. Whether you’re building a plugin, customizing a theme, or debugging a tricky redirect issue — knowing this lifecycle will save you hours. What Are WordPress Hooks? WordPress hooks are designated points in the request lifecycle where you can attach and execute your own code. They come in two types: Actions (do_action) — WordPress announces “this just happened.” You listen and run your own logic at that exact moment using add_action(). Filters (apply_filters) — WordPress announces “I’m about to use this value.” You intercept it, modify it, and return it using add_filter(). // Action example — run your code at a specific moment add_action('init', function() { register_post_type('vehicle', [...]); }); // Filter example — modify a value before WordPress uses it add_filter('the_content', function($content) { return $content . '<p>Thanks for reading!</p>'; }); Think of hooks like electrical outlets built into the walls of a house. The house works perfectly without you plugging anything in — but those outlets are there specifically so you can extend and customize without tearing the walls apart. The WordPress Request Lifecycle Below is the full flow of a WordPress request — from the moment a URL is hit to the moment a template renders. Every 🪝 hookable point is a place where WordPress hooks let you inject your own logic. /index.php ↓ /wp-blog-header.php ↓ wp_load() → /wp-load.php ↓ /wp-config.php ↓ /wp-settings.php ├── All plugins loaded → do_action('plugins_loaded') ├── Widgets init → do_action('widgets_init') └── do_action('init') ← register post types, taxonomies, rewrite rules ↓ wp() → WP::main() ↓ WP::parse_request() ├── Matches URL against rewrite rules ├── Sets query vars └── do_action('parse_request') ← 🪝 hookable ↓ WP::query_posts() → new WP_Query() └── do_action('parse_query') ← 🪝 hookable ↓ WP::handle_404() ↓ WP::send_headers() └── do_action('send_headers') ← 🪝 hookable ↓ do_action('wp') ← 🪝 hookable (full WP context ready) ↓ /wp-includes/template-loader.php ↓ do_action('template_redirect') ← 🪝 hookable (last chance before template) ↓ apply_filters('template_include') ← 🪝 hookable (override template file) ↓ /wp-content/themes/your-theme/index.php ↓ get_header() → do_action('get_header') ← 🪝 hookable get_footer() → do_action('get_footer') ← 🪝 hookable get_sidebar() → do_action('get_sidebar') ← 🪝 hookable the_content() → apply_filters('the_content') ← 🪝 hookable WordPress Request Lifecycle Hooks — When to Use Each Understanding the WordPress request lifecycle means knowing which hook serves which purpose. Here’s a quick reference: HookTypeBest Used Forplugins_loadedActionLoad dependencies, check if other plugins existinitActionRegister post types, taxonomies, rewrite rulesquery_varsFilterAllowlist custom URL query parametersparse_requestActionIntercept URL early, before WP_Query buildsparse_queryActionModify WP_Query object before DB query runssend_headersActionAdd custom HTTP response headerswpActionLogic that needs full WP context (post type, archive, etc.)template_redirectActionRedirects, 404s, access control, before template loadstemplate_includeFilterOverride which template file WordPress loadsthe_contentFilterModify post content before it renders Quick Rule of Thumb Need to act on the URL? → parse_requestNeed to modify the query? → parse_queryNeed WP context (is_single etc)? → wpNeed to redirect? → template_redirectNeed to change the template? → template_includeNeed to tweak rendered content? → the_content One Golden Rule The earlier you hook, the less context you have. The later you hook, the less control you have. Hook too early (like plugins_loaded) and WordPress hasn’t built the query yet — you won’t know if you’re on a single post or an archive. Hook too late (like the_content) and headers are already sent, redirects are impossible, and the template is already decided. The sweet spot depends entirely on what your code needs to know and what it needs to control. Use the lifecycle map above to find that sweet spot every time. Conclusion WordPress’s hook system is what makes it infinitely extensible without ever touching core files. But like any powerful tool, it rewards those who understand it deeply. Next time you’re about to write add_action() or add_filter(), pause for a second and ask — where in the lifecycle does this actually need to run? The answer to that question is often the difference between a clean solution and a frustrating debugging session three months later. Bookmark this page. You’ll be back. To learn more about how hooks are registered internally, refer to the official WordPress Plugin Handbook and the WordPress action reference on developer.wordpress.org.