The Request Lifecycle

This article is part of the WordPress guide. Read the introduction.

Stage 1: index.php

This is the front controller. It’s the first php file called on every request. It’s incredibly simple; here’s its entire code:

PHP
define( 'WP_USE_THEMES', true );
require __DIR__ . '/wp-blog-header.php';

The first line defines a constant that tells WordPress its goal is to display a theme. If you were writing a script that didn’t need to load the theme, you could set this to false. The second line is the handoff, which initiates the rest of the functionality outlined below.

Stage 2: wp-blog-header.php

This file is also very simple. Here are the most significant lines of code in the file:

PHP
require_once __DIR__ . '/wp-load.php';
wp();
require_once ABSPATH . WPINC . '/template-loader.php';

wp-load.php is the main star. It loads the entire environment. The wp() function triggers parsing of the URL and the main database query. template-loader.php decides which template file to use.

Stage 3: wp-load.php

This file searches the current directory and its parent for the wp-config.php file. Why does it search the parent? Because then you can place the wp-config.php file, which contains confidential information, outside of your root directory. That makes it completely inaccessible to the web server, even if the server is (mis)configured to allow viewing php files as text. It’s a hardening technique.

If wp-config.php is not present, a configuration process is initiated. That means loading a few crucial, bare-minimum files required to successfully redirect the user to the /wp-admin/setup-config.php file. The files loaded:

  • /wp-includes/version.php – specifies some version variables, like the wp version or required php version.
  • /wp-includes/compat.php – implementations of PHP functions either missing from older PHP versions or not included by default.
  • /wp-includes/load.php – basic functions needed to load WordPress.
  • /wp-includes/functions.php – more core WordPress procedural functions, many of which would not work at this stage. Crucially, it allows for internationalization to work.

In the typical case, the user will then get redirected to the /wp-admin/setup-config.php file – accessed directly without going through index.php. This file will then guide the user through the process of generating the wp-config.php file (write permissions for the root directory are required for it to work automatically; otherwise, the user is instructed to create the file manually).

Stage 4: wp-config.php

This is the configuration file. It sets up security keys, database credentials, debug configuration, and any other config (you can modify it if you need to). It defines this information by defining constants, e.g., define( ‘DB_PASSWORD’ ‘secret_database_password’). An incomplete list of options that you can override, along with their default values, is available in /wp-includes/default-constants.php.

The last line of the wp-config.php file is:

PHP
require_once ABSPATH . 'wp-settings.php';

Stage 5: wp-settings.php

This is the final file in the chain of setting up the WordPress environment. Its responsibilities are:

  • Include files from the /wp-includes/ directory providing core WordPress functionality.
  • Set global settings and variables (e.g., default constants, language, timezone, etc.).
  • Connect to the database and create the global $wpdb class.
  • Load must-use plugins.
  • Load active plugins.
  • Load the active theme’s functions.php file(s).
  • Set up the current user’s authentication and permissions.

After this file executes, the entire WordPress is “up & running” and loaded into memory, but it still doesn’t know what to display and how to display it. The execution goes back to the wp-blog-header.php file.

Stage 6: wp() in wp-blog-header.php

This function has 2 main objectives: to parse the URL and query the database for the posts. The function itself is actually just a lean wrapper that delegates the work to an object of class WP ($wp). It calls its main() method, which in turn calls 2 very important methods:

  • $wp->parse_request( $query_args )
  • $wp->query_posts()

parse_request() does exactly what you think it does – it parses the request URL. It interacts with the WP_Rewrite class and uses regex to match the URL path to the permalinks structure on the site (the one you set up in Settings -> Permalinks). It then sets those parsed fragments as variables, which will then be used to query the database for matching posts, e.g., a path /category/news/ would become […, ‘category_name’ => ‘news’, …].

The query_posts() method is essentially a wrapper for the WP_Query class. Its goal is to fetch the requested posts from the database. After the method executes, the global $wp_query object will hold all the most important information, such as:

  • $wp_query->posts – an array of WP_Post objects.
  • $wp_query->post_count – the number of posts in the posts array.
  • $wp_query->found_posts – the number of posts that matched the query (can be more than post_count if the result is paged).
  • Flags – like $wp_query->is_single, $wp_query->is_category, etc.

For example, if the path is /category/news/, and the wp() function executes successfully, the result will be a populated $wp_query global object with the posts array containing 10 posts from the news category (by default). If the path is /post-name/, then the result will be a populated $wp_query object with the information and contents of that post, assuming the post exists.

Stage 7: template-loader.php

We now have the content to be displayed. It’s time to display it. Execution flows to the last line of wp-blog-header.php, i.e.:

PHP
require_once ABSPATH . WPINC . '/template-loader.php';

The template-loader.php file is responsible for loading the appropriate template. It defines a static associative array, whose entries follow this pattern:

PHP
[
'is_embed' => 'get_embed_template',
'is_404' => 'get_404_template',
// ...
]

This array is then iterated over (if the WP_USE_THEMES constant defined in index.php is true). Both the key and the value are callbacks – names of functions to be called. The keys are very simple functions that check the flags on the $wp_query object and return their values. Once the key callback returns true, the value callback is called, and the loop is broken out of. The entries in the array are ordered from most to least specific.

The value callbacks are functions responsible for actually finding the correct template to include. Let’s take get_category_template(). It looks for files in the current theme that match WordPress’s template hierarchy, e.g., “category-news.php”, “category.php”, etc. It then includes the most specific one found. The template hierarchy is a topic worth its own section.

If none of the callbacks return true, WordPress defaults to displaying the index.php file (the one in the theme directory, not the front controller).

No more files are called by WordPress. Its job is done. It has set up the entire environment and called the appropriate template defined by the theme used on the site. That’s where the responsibility shifts from WordPress to the website/theme developer.