Фильтровать сообщения из основного запроса

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

Я хочу условно объединить пользовательский тип записей с типом записей “посты”, основываясь на пользовательском поле. Если значение поля равно 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(), чтобы отслеживать данные.

Заключение

Эта конфигурация позволит вам гибко управлять основным запросом и исключать нежелательные посты на вашей главной странице. Вы сможете улучшить пользовательский опыт на сайте, адаптируя отображение контента под определенные условия. В конечном счете, правильная реализация позволит предоставить пользователям именно те посты, которые вы хотите видеть на главной странице, сохраняя при этом производительность вашего сайта.

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

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