4

I'm wondering when does WordPress initiate its main query which sets the global $wp_query and enable us to use has_posts() and the_post() functions. If I create a page using archive template, how does it know how to set its query?

I'm looking at the archive.php in one of the WordPress default themes. They have an archive page but it just calls get_header() and has_posts(), so that means the query is already set. So WordPress routes the url to use the custom post type param in the URL?

If I choose to make custom archive pages, where do I modify the main query? In the new archive template file?

2 Answers 2

2

User Rarst has a very famous answer where he lays out the load process. Looking at this graph whenever wp-blog-header.php gets loaded it calls function wp() which sets up many of WordPress globals like $post and $wp_query. ( Secondary Reference by User Gmazzap )

That's the technical side of things but it looks like the core of your questions is creating your own custom archive pages. WordPress has a Template Hierarchy which allows you to create custom archives for things like Custom Post Types.

Another common way to modify the main query is to use a Hook in your functions.php file called pre_get_posts. This will let you modify the query object before WordPress actually pings to database to get the information which makes it very easy to modify The Loop with different settings. An example could look like this which would modify The Loop to show 20 posts instead of the default 10:

function wpse_265733( $query ) {

    // Don't run on admin
    if( $query->is_admin ) {
        return;
    }

    // Run only on the blog page
    if( is_home() ) {
        $query->set( 'posts_per_page', 20 );    // Set posts per page to 20.
    }

}
add_action( 'pre_get_posts', 'wpse_265733' );
3
  • So my main question really is how WordPress parses the url and from that it sets a few params to go fetch templates and set query vars. I found a really good post roots.io/routing-wp-requests explaining the WordPress routing basics. So from I've understood so far, template files themselves may not set the query (and probably shouldn't?) We'll need to have add hooks to modify/set the main query. Also I wish there's some articles out that explains how WordPress is parsing urls to retrieve custom post types or taxonomy terms and then setting query according to these functions. Commented May 4, 2017 at 21:43
  • @TurtleTread I'm the author of that article. As written there, WordPress stores rewrite rules, that are a map from URLs to query arguments. For CPT and custom taxonomies, when you register them, WP creates rewrite rules for them, so the query is set in the same way. After query has been set, WP loads template-loader.php that based on the type of query loads the related template. You can see the source code for it here: github.com/WordPress/WordPress/blob/master/wp-includes/…
    – gmazzap
    Commented May 7, 2017 at 8:33
  • @TurtleTread So when templates are loaded, a query is already set from URL (that query is known as "main query") otherwise WordPress wouldn't know which template to load. If you create queries in templates, those are secondary queries that might be used to show different posts. To change the main query you should use pre_get_posts hook as suggested in this answer.
    – gmazzap
    Commented May 7, 2017 at 8:37
3

After plugins and theme functions are loaded, WordPress parses the incoming request into query variables, by going through the list of rewrite rules to find a pattern that matches the request.

There are a number of default rules for the built in types- pages, various archives, single views, pagination, feeds. You can add your own rules or endpoints manually, or register new content types which can auto-generate all those rules for your custom content.

Once the request is converted to query variables, the query is run. In many cases, the results of the query are what determine which template gets loaded.

Then of course the template is loaded, and everything is good.

So that said, there are a number of actions and filters available to let you modify things at every step. To see a more detailed view of the process and what some of those things are, have a look at the Action Reference.

The simplest and most common method is the pre_get_posts action. This exposes the query variables and lets you modify things before the query is run. See WP_Query for a reference of query vars.

If that doesn't satisfy your needs, have a look at the request filter, which allows more radical query manipulation, as it runs directly after query var extraction, before WordPress has made any decisions about the type of request that's happening.

3
  • A lot of the themes have the templates for archives, but to use these, we need to either follow the url convention so that they set the correct query. Or we need to somehow pass a WP_Query object to start the loop? So these templates do not set the query themselves? which does make sense. But where is the common place to pass the query based on URLs? If we want to filter the query with post_type but use the same template, do we handle that in theme functions file or maybe a plugin that parses the url and determine the query params? Commented May 3, 2017 at 21:46
  • @TurtleTread It's a little difficult to get what you're referring to but you can modify the query in pre_get_posts based on $_GET vars in the URL.
    – Howdy_McGee
    Commented May 3, 2017 at 21:50
  • @TurtleTread I think pre_get_posts is what you're after. Typically archives are per-post type, but it's not uncommon to modify the default posts page query to do things like add additional post types, or filter on meta data. But yes, if a template utilizes the main query and regular loop, it is using the query that has run before that template was loaded.
    – Milo
    Commented May 3, 2017 at 23:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.