admin管理员组

文章数量:1402793

I am using a custom template for a members page which looks something like this

<?php
/**
 * Template Name: Our Members
 *
 * @package Demo
 */

$args = [
    "post_type" => "members",
    "posts_per_page" => 6,
    "s" => "ma",
    "tax_query" => [
        [
            "taxonomy" => "membership-type",
            "field" => "slug",
            "terms" => [
                "a",
                "b",
            ],
        ],
        [
            "taxonomy" => "region",
            "field" => "slug",
            "terms" => [
                "a",
                "b",
            ],
        ],
    ],
];
$members = fetch_members_posts($args);

get_header();
var_dump($members);
get_footer();

The function fetch_members_posts is defined in functions.php, and it looks like so

function fetch_members_posts(array $args = []) {

    $posts = new WP_Query([
        ...[
            'post_type' => 'members',
            'posts_per_page' => 6,
            'post_status' => 'publish',
        ],
        ...$args,
    ]);
    wp_reset_query();

    return $posts;
}

When I run the one with wp_query I get no results in var_dump($members->posts); and when I check the query that was run using var_dump($members->request) I see the following SELECT * FROM wp_posts WHERE 1=2. Strange thing is, it only returns the correct results when I remove or comment out the line with the search term "s" => "ma",.

But when I change the function to fetch_members_posts to use get_posts like so

function fetch_members_posts(array $args = []) {
    return get_posts([
        ...[
            'post_type' => 'members',
            'posts_per_page' => 6,
            'post_status' => 'publish',
        ],
        ...$args,
    ]);
}

Everything seem to work great as in returning the expected posts, even without removing or commenting out the search term "s" => "ma",.

What am I missing here?

I am using a custom template for a members page which looks something like this

<?php
/**
 * Template Name: Our Members
 *
 * @package Demo
 */

$args = [
    "post_type" => "members",
    "posts_per_page" => 6,
    "s" => "ma",
    "tax_query" => [
        [
            "taxonomy" => "membership-type",
            "field" => "slug",
            "terms" => [
                "a",
                "b",
            ],
        ],
        [
            "taxonomy" => "region",
            "field" => "slug",
            "terms" => [
                "a",
                "b",
            ],
        ],
    ],
];
$members = fetch_members_posts($args);

get_header();
var_dump($members);
get_footer();

The function fetch_members_posts is defined in functions.php, and it looks like so

function fetch_members_posts(array $args = []) {

    $posts = new WP_Query([
        ...[
            'post_type' => 'members',
            'posts_per_page' => 6,
            'post_status' => 'publish',
        ],
        ...$args,
    ]);
    wp_reset_query();

    return $posts;
}

When I run the one with wp_query I get no results in var_dump($members->posts); and when I check the query that was run using var_dump($members->request) I see the following SELECT * FROM wp_posts WHERE 1=2. Strange thing is, it only returns the correct results when I remove or comment out the line with the search term "s" => "ma",.

But when I change the function to fetch_members_posts to use get_posts like so

function fetch_members_posts(array $args = []) {
    return get_posts([
        ...[
            'post_type' => 'members',
            'posts_per_page' => 6,
            'post_status' => 'publish',
        ],
        ...$args,
    ]);
}

Everything seem to work great as in returning the expected posts, even without removing or commenting out the search term "s" => "ma",.

What am I missing here?

Share Improve this question asked Mar 12 at 17:33 kellymandemkellymandem 1013 bronze badges 4
  • Is this members query intended to be the main query for the page, or will the page contain regular content added through the editor too? As it stands it looks like this should be a CPT archive rather than a Page template. – Chris Cox Commented Mar 12 at 17:45
  • @ChrisCox The members query is intended to be used alongside the other page content that is added on the backend through ACF fields. – kellymandem Commented Mar 12 at 18:16
  • wp_reset_query should only be used to cleanup after query_posts() calls, so you should never use either of them. Fundamentally though get_posts and new WP_Query() do not give you the same things. One gives you an array of posts, the other gives you an object of type WP_Query – Tom J Nowell Commented Mar 12 at 19:05
  • I'd also move your query to after your header, as the sites header can't be sent until your query completes, meanwhile the browser is sitting idle waiting for data – Tom J Nowell Commented Mar 12 at 19:17
Add a comment  | 

1 Answer 1

Reset to default 0

The main problem is a misunderstanding of PHP objects and the 2 methods you're using:

$a = get_posts( ... );
$b = new WP_Query( ... );
  • $a is an array of WP_Post objects
    • e.g. foreach ( $a as $p ) { ... }
  • $b is an object of type WP_Query
    • e.g. while ( $b->have_posts() ) { $b->the_post(); .... }

Most importantly, get_posts is a wrapper around WP_Query! So much so that the array of posts is $b->posts, but beware that by accessing it you skip any lazy loading optimisations in place. The same is somewhat true of using get_posts, and you would still need to call setup_postdata inside the loop for each post to set the current post, followed by wp_reset_postdata at the end.

A Note on wp_reset_query

This function is not for cleaning up after get_posts or WP_Query. Though it will appear to work, it does more than that. This is because it's intended to reset the query itself after using query_posts(...) to overwrite the main query. Since query_posts is a major mistake in 99% of cases it's safe to say you should never use it, and neither should you use wp_reset_query.

Instead, this is how you perform a standard post loop using a query:

$args = [ ... ];
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
    while( $query->have_posts() ) {
        $query->the_post();
        // output inner loop, get_the_ID and standard functions such as `the_title()` will work in here
    }
    wp_reset_postdata();
}

Notice I did not do foreach ( $query->posts as $post ) { as this would not set the current post globals, and it would not perform lifecycle filters and hooks. I also only call wp_reset_postdata at the very end after the loop, but, I do it inside the if condition so it does not happen if there are no posts. I also checked if the query had posts, this gives an opportunity to print out things before/after the loop such as <ul> and </ul> etc

Further reading:

  • https://developer.wordpress/reference/functions/get_posts/
  • https://www.hostinger/tutorials/wordpress-wp_query#1_Create_a_Loop

本文标签: wp queryget posts returns results but wpquery does not