Вопрос или проблема
Я хочу условно объединить пользовательский тип записей с типом записей “посты”, основываясь на пользовательском поле. Если значение поля равно 1, тогда я хочу, чтобы эти пользовательские записи отображались в том же цикле, что и посты на главной странице. Я могу объединить пользовательский тип записей с типом записей по умолчанию, и могу создать массив ID записей для исключения с помощью post__not_in
, но не могу понять, как это применить к основному циклу. Вот мой код для шаблона index.php ниже:
if (is_home()) {
$exclude = array();
$newsQuery = new WP_Query (array(
"post_type" => "news",
"meta_key" => "post_to_blog",
"meta_value" => 1,
"meta_compare" => "!=",
"posts_per_page" => "-1",
));
while ($newsQuery->have_posts()) {
$newsQuery->the_post();
array_push($exclude, get_the_ID());
}
wp_reset_query();
}
if (have_posts()) {
while (have_posts()) {
the_post();
get_template_part("content", get_post_format());
}
}
if ($wp_query->max_num_pages > 1) {
echo "<div class=\"pagination\">";
kriesi_pagination();
echo "</div>";
}
А вот что я делаю, чтобы показать пользовательский тип записей в основном запросе в functions.php:
function custom_home_loop($query) {
if ($query->is_main_query() && is_home()) {
$query->set("post_type", array("post", "news"));
}
}
add_filter("pre_get_posts", "custom_home_loop");
Есть ли способ объединить эти два? Я бы хотел сделать что-то вроде $query->set("post__not_in",$exclude);
, но это не работает, когда я пробую. Ошибки нет, посты просто продолжают появляться. Я пытался переместить код $exclude
в функцию custom_home_loop
, но по какой-то причине получаю ошибку переполнения памяти.
Непроверено:
function custom_home_exclude( $where="" ) {
$exclude = array();
$newsQuery = new WP_Query (array(
"post_type" => "news",
"meta_key" => "post_to_blog",
"meta_value" => 1,
"meta_compare" => "!=",
"posts_per_page" => "-1",
));
while ($newsQuery->have_posts()) {
$newsQuery->the_post();
array_push($exclude, get_the_ID());
}
wp_reset_query();
$exclude = join(',', $exclude);
$where .= " AND `ID` NOT IN ($exclude)";
return $where;
}
function custom_home_loop($query) {
if ($query->is_main_query() && is_home()) {
$query->set("post_type", array("post", "news"));
add_filter( 'posts_where', 'custom_home_exclude' );
}
}
add_filter("pre_get_posts", "custom_home_loop");
Ответ или решение
Фильтрация Постов из Основного Запроса в WordPress
Для решения задачи условного объединения пользовательских типов постов и стандартного типа постов в WordPress, необходимо различать подходы. Вы собираетесь отображать пользовательские посты в главном цикле на главной странице на основе значения пользовательского поля, что является распространенной практикой для кастомизации контента.
Пошаговое Реализация
Ваша задача сводится к одному важному аспекту: объединение пользовательских постов (в вашем случае news
) с обычными постами. При этом необходимо исключить посты, значение поля post_to_blog
которых равно 1. Давайте рассмотрим, как это можно реализовать корректно и без ошибок.
1. Модификация Основного Запроса
Ваша текущая реализация функции custom_home_loop
позволяет изменить типы постов в основном запросе. Однако для корректного исключения постов стоит заменить логику на более надёжную, которая будет использовать post__not_in
. Убедитесь, что массив $exclude
, который вы хотите использовать для исключения постов, создается в правильном контексте.
Вот как можно переписать ваши функции:
function custom_home_loop($query) {
if ($query->is_main_query() && is_home()) {
// Получаем все посты типа "news" с пользовательским полем "post_to_blog" не равным 1
$exclude = array();
$newsQuery = new WP_Query(array(
'post_type' => 'news',
'meta_key' => 'post_to_blog',
'meta_value' => 1,
'meta_compare' => '==', // Сравниваем с 1
'posts_per_page' => -1,
));
// Сбор ID постов для исключения
while ($newsQuery->have_posts()) {
$newsQuery->the_post();
$exclude[] = get_the_ID();
}
wp_reset_postdata(); // Используем wp_reset_postdata вместо wp_reset_query
// Устанавливаем параметры основного запроса
$query->set('post_type', array('post', 'news'));
$query->set('post__not_in', $exclude); // Исключаем посты по IDs
}
}
add_filter('pre_get_posts', 'custom_home_loop');
2. Пояснения к Коду
-
Проверка Основного Запроса: Убедитесь, что вы используете
is_main_query()
, чтобы избежать изменения других запросов на странице. -
Использование параметров: После получения всех необходимых постов типа
news
, вы добавляете их IDs в массив$exclude
, который затем передается в основной запрос черезpost__not_in
. -
wp_reset_postdata(): Использование
wp_reset_postdata()
вместоwp_reset_query()
в этом контексте более предпочтительно, так как оно сбрасывает глобальную переменную$post
, не затрагивая другие аспекты запросов.
3. Возможные Ошибки и Предостережения
-
Ошибка памяти: Если вы сталкиваетесь с ошибкой переполнения памяти, это может быть вызвано тем, что вы пытались запрашивать слишком много данных в цикле или неправильно использовали глобальные переменные. Убедитесь, что количество постов, которые вы обрабатываете, адекватно.
-
Отладка: Если после всех изменений все еще присутствуют проблемы с отображением постов, убедитесь, что ваш запрос работает, и используйте инструменты отладки, такие как
var_dump()
илиerror_log()
, чтобы отслеживать данные.
Заключение
Эта конфигурация позволит вам гибко управлять основным запросом и исключать нежелательные посты на вашей главной странице. Вы сможете улучшить пользовательский опыт на сайте, адаптируя отображение контента под определенные условия. В конечном счете, правильная реализация позволит предоставить пользователям именно те посты, которые вы хотите видеть на главной странице, сохраняя при этом производительность вашего сайта.