Attention Interested in functions, hooks, classes, or methods? Check out the new WordPress Code Reference!

Query Overview

This article is an overview for developers of the process WordPress uses to build your blog pages, and how plugins can modify that process. It is aimed at developers of plugins that will do advanced queries and permalinks, and also at developers who want to understand WordPress better, in order to add new features to the core of WordPress or fix WordPress bugs.

For more details, you'll need to read the WordPress core PHP files and functions mentioned.

So, here are the steps WordPress uses to decide what posts or pages to display on a page, and display them:

  1. When a visitor first clicks on or types a URL for a page that is part of your blog, WordPress starts by running a few core files (wp-config.php, wp-settings.php, etc.) If you are interested in the specifics of the file loading order, start at index.php and follow the chain of files as each PHP file includes/requires additional PHP files (or read this excellent post at humanshell.net)
  2. WordPress loads and initializes any plugins you have activated (calls the plugin init actions).
  3. WordPress loads the "text domain" for internationalization, and the functions.php file from the currently active theme.
  4. WordPress runs the wp() function (in wp-includes/functions.php), which calls $wp->main() ($wp is an object of class WP, which is defined in wp-includes/class-wp.php). This tells WordPress to:
    1. Parse the URL into a query specification using WP->parse_request() -- more on that below.
    2. Set all the is_ variables that are used by Conditional Tags using $wp_query->parse_query() ($wp_query is an object of class WP_Query, which is defined in wp-includes/query.php). Note that in spite of this function's name, in this case WP_Query->parse_query doesn't actually do any parsing for us, since that is done before-hand by WP->parse_request().
    3. Convert the query specification into a MySQL database query, and run the database query to get the list of posts, in function WP_Query->get_posts(). Save the posts in the $wp_query object to be used in the WordPress Loop.
    4. Handle 404 errors.
    5. Send the blog's HTTP headers.
    6. Set up some variables for the WordPress Loop.
  5. WordPress loads your template, figures out which template file to use according to the Template Hierarchy, and runs that file (basically doing whatever your template file says to do). Or, WordPress could run one of the feed files (such as wp-rss2.php) instead.
  6. Generally, the template or feed file runs the WordPress Loop to print blog posts or a static page.
  7. The template or feed file will also likely print out permalinks to some archives, categories, or posts using built-in WordPress functions.

More on WP->parse_request()

As mentioned above, WP->parse_request() (part of class WP in wp-includes/class-wp.php) parses a URL into a query specification. Here is a summary of the steps it uses to do this:

  1. Strips the GET variable section out of the URL (i.e. anything after a "?" in the URL). Also strips out the blog's home URL.
  2. Obtains the rewrite rules that are currently in effect, by calling $wp_rewrite->wp_rewrite_rules() ($wp_rewrite is an object of class WP_Rewrite, which is defined in wp-includes/rewrite.php). The rewrite rules are basically a set of pattern matching rules for WordPress permalinks, with a specification of what to do if the pattern matches. For instance, by default there is a rule that would match a stripped permalink like category/abc, and its specification says that it means the "abc" category was requested. There is also a rewrite rule for the home page (nothing after the blog URL).
  3. Goes through the rewrite rules in order, until it finds a match between a rewrite rule and the permalink. If nothing is found, it's a 404 error. If a match is found, WordPress extracts the information according to the rule specification.
  4. Obtains the list of query variables that is currently in effect. For each query variable, WordPress checks to see if it has been set by permalink parsing, POST submission, or GET submission, and if so, WordPress saves the variable's value into the query specification array ($wp->query_vars, part of class WP in wp-includes/class-wp.php).

What Plugins can Modify

Here is an overview of the things a plugin can do to modify the default query and permalink behavior described above. Many of these modifications are described (with examples) in the article Custom Queries.

  • Add, modify, or remove rewrite rules, to affect how permalinks are parsed. This is generally not done with filters and actions, but instead by calling functions in wp-includes/rewrite.php, such as add_rewrite_rule, add_rewrite_endpoint, etc. This can be a bit tricky, because WP_Rewrite->wp_rewrite_rules() usually just gets the previously-saved set of rewrite rules (they are saved in the WordPress database as option "rewrite_rules"). So if you want to modify rewrite rules, you will need to call $wp_rewrite->flush_rules() to force them to recalculate. You'll need to do this in your plugin's activation/deactivation/uninstall action, so that it happens early enough in the process. It's extremly important to not do this on every request. Do this only during plugin activation and similar.
  • Add or remove query variables, to affect which variables are saved in the query specification from POST, GET, and permalink requests (query_vars filter).
  • Modify the query specification, after variable values are saved (request filter or parse_request action; if you want to use conditional tag tests, use the parse_query or pre_get_posts action, as these run after the is_ variables are set).
  • Modify the MySQL database query, after it is created from the query specification using the following filters:
    • posts_where
    • posts_join
    • posts_groupby
    • posts_orderby
    • posts_distinct
    • posts_fields
    • post_limits
    • posts_where_paged
    • posts_join_paged
    • posts_request
  • Modify the results of the database query (the_posts filter).
  • Override the default template file choice (template_redirect action).



Code Documentation