Вопрос или проблема
Я использую пользовательский шаблон для страницы участников, который выглядит примерно так:
<?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, но они работают немного по-разному:
-
WP_Query: Это объект, который позволяет выполнять сложные запросы к базе данных. Он возвращает объект типа
WP_Query
, который предоставляет вам методы для работы с результатами, такие какhave_posts()
,the_post()
и другие. Он требует вызова функцииwp_reset_postdata()
после завершения цикла, чтобы восстановить глобальные постовые данные. -
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
и уделяете внимание особенностям каждого элемента запроса, вы можете избегать таких нестыковок. Настоятельно рекомендуется детально проверять каждый элемент запроса и логику работы с данными, чтобы обеспечить правильное выполнение и отображение результатов.