结合 WP_Query 与主查询(the Main Query)

到目前为止,在这个系列中,你已经学习了如何在你的主题或插件中使用 WP_Query 创建自定义查询。在大多数情况下,你将使用 WP_Query 设置独立于主查询(the Main Query)的参数来查询,但如果你希望包含主查询的参数在你的参数中,你该怎么做?

注:由于时间精力有限,本教程没办法翻译分享,希望朋友们可以加入我们,帮助我们进行翻译,有小酬谢,有意者请联系倡萌QQ 745722006(注明:教程翻译)。

以下为原文:http://code.tutsplus.com/tutorials/combining-wp_query-with-the-main-query–cms-23209

So far in this series you’ve learned how to use WP_Query to create custom queries for use in your theme or plugins.

In most cases, you’ll use WP_Query with a completely new set of arguments which are separate from that in the main query, but what if you want to include the main query in your arguments?

Examples of when you might want to do this include:

  • on a category or taxonomy page, displaying only posts of one post type
  • on a category page, displaying posts with the current category and another category or a tag or taxonomy term
  • on a page for a post type, just displaying posts with certain metadata

I could go on—there are plenty of opportunities for combining the main query with your own custom query.

I’m going to demonstrate this with three examples: the first one will be a simple example with one loop; the second will use foreach to output multiple loops, one for each post type; and the third will output two post types on a category archive by using two separate queries.

Defining a Variable Based on the Main Query

However you’re going to combine your main query with WP_Query, you need to store the current query object in a way that makes it easy to use in your WP_Query arguments. The easiest way to do this is by assigning it to a variable.

You do this before defining your WP_Query arguments, like so:

1
$mainquery = get_queried_object();

The get_queried_object() function returns the currently queried object, whatever that may be. On a single post, it will just return the post object, while on an archive it will return the category, tag, term object or whatever object relates to the archive. It returns the ID of the queried object.

You can then use this $mainquery variable in your WP_Query arguments. Now let’s take a look at some examples.

Example 1: Displaying Only Posts of One Post Type on a Category Page

Let’s say your site has a custom post type added to it and you’ve enabled categories for that custom post type. On the category archive for each category, you don’t want to display posts: instead you want to display posts of your new post type—let’s call it product.

Your query might look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
 
$mainquery = get_queried_object();
 
$args = array (
    'category_name' => $mainquery->slug,
    'post_type' => 'product'
);
 
// Custom query.
$query = new WP_Query( $args );
 
// Check that we have query results.
if ( $query->have_posts() ) {
 
    // Start looping over the query results.
    while ( $query->have_posts() ) {
 
        $query->the_post();
 
        // Contents of the queried post results go here.
 
    }
 
}
 
// Restore original post data.
wp_reset_postdata();
 
?>

Because the category_name parameter I’ve used above takes the category slug as its argument, you need to add ->slug after the variable to output the category slug.

This gives you a query which fetches posts of the product post type from the database with the currently queried category. You’d use it on the category.php page template.

Note: You could also achieve this result using the pre_get_posts hook to amend the main query, combined with a conditional function to check for category archives.

Example 2: Combining the Main Query With WP_Query and foreach to Output Multiple Loops

The next example will output all of the posts for the current category page, but instead of showing them all in one block it will separate them by post type.

This means you can sort your post types into blocks or columns on your page using CSS, or just separate them out into different lists.

To do this, you’d use the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
 
$mainquery = get_queried_object();
 
$post_types = get_post_types();
 
foreach ( $post_types as $post_type ) {
 
    $args = array(
        'category_name' => $mainquery->slug,
        'post_type' => $post_type
    );
 
    // Custom query.
    $query = new WP_Query( $args );
 
    // Check that we have query results.
    if ( $query->have_posts() ) {
 
        // Start looping over the query results.
        while ( $query->have_posts() ) {
 
            $query->the_post();
 
            // Contents of the queried post results go here.
 
        }
 
    }
 
    // Restore original post data.
    wp_reset_postdata();
 
}
 
?>

This uses the $mainquery variable we used before, but it also adds a $post_types variable to store all of the post types registered on the site, and a $post_type variable to store each individual post type in turn.

Example 3: Two Separate Queries for Two Post Types

The final example is similar to the second one, but separates out the post types into two separate queries, each with its own distinct loop. This gives you more control over what’s displayed for each, so you could display posts differently from products, maybe including a featured image for products or giving them a different layout.

Let’s say your site has the product post type registered, with categories enabled for it, and you’re also writing blog posts with the same categories. On each category archive page you want to display the most recent ten posts, and then you want to display a list of all products in the same category.

To do this, you’d use something like this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php
 
$mainquery = get_queried_object();
 
// First query arguments for posts.
$args = array (
    'category_name' => $mainquery->slug,
    'post_type' => 'post',
    'posts_per_page' => '10'
);
 
// Custom query.
$query = new WP_Query( $args );
 
// Check that we have query results.
if ( $query->have_posts() ) {
 
    // Start looping over the query results.
    while ( $query->have_posts() ) {
 
        $query->the_post();
 
        // Contents of the queried post results go here.
 
    }
 
}
 
// Restore original post data.
wp_reset_postdata();
 
// Second query arguments for products.
$args = array (
    'category_name' => $mainquery->slug,
    'post_type' => 'product',
    'posts_per_page' => '-1'
);
 
// Custom query.
$query = new WP_Query( $args );
 
// Check that we have query results.
if ( $query->have_posts() ) {
 
    // Start looping over the query results.
    while ( $query->have_posts() ) {
 
        $query->the_post();
 
        // Contents of the queried post results go here.
 
    }
 
}
 
// Restore original post data.
wp_reset_postdata();
 
?>

You’d then write each loop differently to output different data for each post type.

Summary

As you can see from the examples above, it’s possible to use WP_Query not only to create completely custom queries separate from the main query, but also to incorporate the currently queried object and create more powerful queries on archive pages.

The examples above can also be done with other archive types: for taxonomies, authors, dates and more. See if you can come up with more possibilities!