get_posts возвращает результаты, но WP_Query не возвращает.

Вопрос или проблема

Я использую пользовательский шаблон для страницы участников, который выглядит примерно так:

<?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();

Функция fetch_members_posts определена в functions.php и выглядит так:

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;
}

Когда я запускаю с wp_query, я не получаю результатов в var_dump($members->posts);, и когда я проверяю запрос, который был выполнен, используя var_dump($members->request), я вижу следующее SELECT * FROM wp_posts WHERE 1=2.
Странно, но корректные результаты возвращаются, только если я удаляю или комментирую строку с поисковым термином "s" => "ma",.

Но когда я изменяю функцию fetch_members_posts, чтобы использовать get_posts следующим образом:

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

Все, кажется, работает отлично, возвращая ожидаемые публикации, даже без удаления или комментирования строки с поисковым термином "s" => "ma",.

Что я упускаю?

Основная проблема заключается в неправильном понимании объектов PHP и двух используемых методов:

$a = get_posts( ... );
$b = new WP_Query( ... );
  • $a – это массив объектов WP_Post
    • например, foreach ( $a as $p ) { ... }
  • $b – это объект типа WP_Query
    • например, while ( $b->have_posts() ) { $b->the_post(); .... }

Наиболее важно, что get_posts является оболочкой вокруг WP_Query! Настолько, что массив публикаций находится в $b->posts, но имейте в виду, что, при обращении к нему, вы пропускаете любые оптимизации “ленивой” загрузки. То же самое в некоторой степени верно и при использовании get_posts, и вы все равно должны вызывать setup_postdata внутри цикла для каждой публикации, чтобы установить текущую публикацию, а затем вызвать wp_reset_postdata в конце.

Замечание о wp_reset_query

Эта функция не предназначена для очистки после get_posts или WP_Query. Хотя она и может показаться работающей, она делает больше, чем просто это. Потому что она предназначена для сброса самого запроса после использования query_posts(...) для перезаписи основного запроса. Поскольку query_posts является серьезной ошибкой в 99% случаев, можно с уверенностью сказать, что вы никогда не должны его использовать, и не должны использовать wp_reset_query.

Вместо этого, вот как следует выполнять стандартный цикл публикаций с использованием запроса:

$args = [ ... ];
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
    while( $query->have_posts() ) {
        $query->the_post();
        // вывод внутреннего цикла, get_the_ID и стандартные функции, такие как `the_title()`, будут работать здесь
    }
    wp_reset_postdata();
}

Обратите внимание, что я не выполнял foreach ( $query->posts as $post ) {, так как это не устанавливает параметры глобальной текущей публикации и не выполняет фильтры и хуки жизненного цикла. Я также вызываю wp_reset_postdata только в самом конце после цикла, но делаю это внутри условия if, чтобы это не происходило, если публикаций нет. Я также проверил, есть ли в запросе публикации, это дает возможность выводить что-то до/после цикла, например, <ul> и </ul> и т.д.

Дополнительная информация:

Ответ или решение

Конфликт между get_posts и WP_Query в вашем шаблоне WordPress может создавать путаницу, особенно если результаты возвращаются правильно с использованием get_posts, но не работают с WP_Query. Разобраться в этом конфликте поможет понимание основных принципов работы этих функций и особенности реализации в коде.

Теория

get_posts и WP_Query — это два способа получения постов в WordPress, но они работают немного по-разному:

  1. WP_Query: Это объект, который позволяет выполнять сложные запросы к базе данных. Он возвращает объект типа WP_Query, который предоставляет вам методы для работы с результатами, такие как have_posts(), the_post() и другие. Он требует вызова функции wp_reset_postdata() после завершения цикла, чтобы восстановить глобальные постовые данные.

  2. get_posts: Это простейший способ получения постов. Фактически, это обертка над WP_Query, которая просто возвращает массив объектов WP_Post. Не требует вызова wp_reset_postdata() из-за своей упрощенной природы.

Пример

В вашей изначальной функции fetch_members_posts вы использовали WP_Query следующим образом:

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

Использование wp_reset_query() здесь вводит в заблуждение, так как эта функция предназначена для сброса главного запроса, если он был изменен с помощью query_posts(). В вашем случае, это может неправильно сбрасывать состояние, что, вероятно, и приводит к некорректным результатам. Вместо этого нужно использовать wp_reset_postdata(), чтобы корректно сбросить данные поста после работы с объектом WP_Query.

Заметьте, что при добавлении поисковой строки "s" => "ma", ваш запрос возвращает SELECT * FROM wp_posts WHERE 1=2, что указывает на то, что запрос не находит соответствующих постов. Это может быть связано с отсутствием поддержки поисковых терминов в сочетании с указанными таксономическими запросами.

Применение

Для решения вашей проблемы я рекомендую придерживаться следующего структуры кода:

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

    $query_args = array_merge($default_args, $args);

    $query = new WP_Query($query_args);

    if ($query->have_posts()) {
        // Другие операции с постами
        while ($query->have_posts()) {
            $query->the_post();
            // Здесь можно выводить необходимую информацию о постах
        }
        wp_reset_postdata();
    } else {
        // Логика для обработки случая, когда постов нет
    }

    return $query;
}

Попробуйте упростить проверки и логику, когда вы добавляете поиск. Например:

  • Убедитесь, что в полях поиска (например, название, содержание) действительно есть данные, по которым может быть выполнен поиск, соответствующий термину "ma".
  • Проверьте, как поисковый запрос в WP_Query взаимодействует с таксономическими запросами. Возможно, вам нужно сделать более таргетированное уточнение для поиска, гарантируя, что он применим к конкретным полям.

Заключение

Проблемы, связанные с WP_Query и get_posts, зачастую связаны с недопониманием их различий и ошибками в реализации цикла запросов. Убедившись, что вы правильно используете методы WP_Query и уделяете внимание особенностям каждого элемента запроса, вы можете избегать таких нестыковок. Настоятельно рекомендуется детально проверять каждый элемент запроса и логику работы с данными, чтобы обеспечить правильное выполнение и отображение результатов.

Оцените материал
Добавить комментарий

Капча загружается...