$query->is_main_query() игнорирует tax_query запроса

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

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

else if ( isset( $_GET['category'] ) && !is_admin()  ) {
    $_GET   = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
    $tax_query = array(
        array(
            'taxonomy' => 'events-category',
            'field' => 'slug',
            'terms' => array( strtolower( $_GET['category'] ) ),
        ),
    );
    $query->set( 'tax_query', $tax_query );
}

Кто-то предложил изменить условие и добавить $query->is_main_query(), чтобы избежать вмешательства в запрос меню:

else if ( isset( $_GET['category'] ) && !is_admin() && $query->is_main_query()  ) {

Я изменил это, и меню теперь отображается, но запрос таксономии теперь полностью игнорируется, и отображаются все посты.

Почему $query->is_main_query() изменяет запрос таксономии? Я в полном недоумении.

В вашей оригинальной настройке все запросы категорий на фронтенде подвергались воздействию фильтра pre_get_posts, который вы определили. Поэтому и происходило вмешательство в запрос меню. Затем вы добавили дополнительное условие is_main_query. В результате оба, и меню, и ваш основной цикл, больше не подвергались воздействию фильтра.

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

Если вы сами написали эту тему, вы могли бы упорядочить код, чтобы получить основной запрос и применить фильтр. В противном случае вы могли бы изучить код, чтобы выяснить, заданы ли какие-либо аргументы, которые вы могли бы проверить с помощью get метода, чтобы убедиться, что вы выборочно нацеливаетесь на правильный запрос вместо использования is_main_query.

__(‘make’),
‘rewrite’ => array(‘slug’ => ‘make’),
‘hierarchical’ => true,
));

// Город
register_taxonomy(‘city’, ‘product’, array(
‘label’ => __(‘Город’),
‘rewrite’ => array(‘slug’ => ‘city’),
‘hierarchical’ => true,
));

// Год
register_taxonomy(‘year’, ‘product’, array(
‘label’ => __(‘Год’),
‘rewrite’ => array(‘slug’ => ‘year’),
‘hierarchical’ => true,
));

// Цвет
register_taxonomy(‘color’, ‘product’, array(
‘label’ => __(‘Цвет’),
‘rewrite’ => array(‘slug’ => ‘color’),
‘hierarchical’ => true,
));
}
add_action(‘init’, ‘wc_register_custom_taxonomies’);

function wc_filter_form() {
?>

<form method="GET" id="filter">
    <?php
    wp_dropdown_categories(array(
        'show_option_all' => 'Выберите марку',
        'taxonomy' => 'make',
        'name' => 'make',
        'value_field' => 'slug',
    ));

    wp_dropdown_categories(array(
        'show_option_all' => 'Выберите город',
        'taxonomy' => 'city',
        'name' => 'city',
        'value_field' => 'slug',
    ));

    wp_dropdown_categories(array(
        'show_option_all' => 'Выберите год',
        'taxonomy' => 'year',
        'name' => 'year',
        'value_field' => 'slug',
    ));

    wp_dropdown_categories(array(
        'show_option_all' => 'Выберите цвет',
        'taxonomy' => 'color',
        'name' => 'color',
        'value_field' => 'slug',
    ));
    ?>
    <input type="submit" value="Фильтр">
</form>
<?php

}
add_action(‘woocommerce_before_XXX_loop’, ‘wc_filter_form’);#

function wc_filter_products($query) {
if (!is_admin() && $query->is_main_query() && is_shop()) {
$tax_query = array(‘relation’ => ‘AND’);

    if (!empty($_GET['make'])) {
        $tax_query[] = array(
            'taxonomy' => 'make',
            'field' => 'slug',
            'terms' => sanitize_text_field($_GET['make']),
        );
    }

    if (!empty($_GET['city'])) {
        $tax_query[] = array(
            'taxonomy' => 'city',
            'field' => 'slug',
            'terms' => sanitize_text_field($_GET['city']),
        );
    }

    if (!empty($_GET['year'])) {
        $tax_query[] = array(
            'taxonomy' => 'year',
            'field' => 'slug',
            'terms' => sanitize_text_field($_GET['year']),
        );
    }

    if (!empty($_GET['color'])) {
        $tax_query[] = array(
            'taxonomy' => 'color',
            'field' => 'slug',
            'terms' => sanitize_text_field($_GET['color']),
        );
    }

    if (!empty($tax_query)) {
        $query->set('tax_query', $tax_query);
    }
}

}
add_action(‘pre_get_posts’, ‘wc_filter_products’);

function wc_filter_form_shortcode() {
ob_start(); // Начать буферизацию вывода
?>

<?php
wp_dropdown_categories(array(
‘show_option_all’ => ‘Выберите марку’,
‘taxonomy’ => ‘make’,
‘name’ => ‘make’,
‘value_field’ => ‘slug’,
));

    wp_dropdown_categories(array(
        'show_option_all' => 'Выберите город',
        'taxonomy' => 'city',
        'name' => 'city',
        'value_field' => 'slug',
    ));

    wp_dropdown_categories(array(
        'show_option_all' => 'Выберите год',
        'taxonomy' => 'year',
        'name' => 'year',
        'value_field' => 'slug',
    ));

    wp_dropdown_categories(array(
        'show_option_all' => 'Выберите цвет',
        'taxonomy' => 'color',
        'name' => 'color',
        'value_field' => 'slug',
    ));
    ?>
    <input type="submit" value="Фильтр">
</form>
<?php
return ob_get_clean(); // Вернуть буферизованный контент

}
add_shortcode(‘wc_filter_form’, ‘wc_filter_form_shortcode’);

Что не так? Когда я открываю страницы, открывается страница блога статьи.

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

Ваша проблема связана с тем, как вы используете is_main_query() в условии вашего фильтра pre_get_posts. Давайте подробно разберём вашу ситуацию и предложим решение.

Проблема

Когда вы добавили условие if ( isset( $_GET['category'] ) && !is_admin() && $query->is_main_query() ), это ограничивает удостоверение выполнения фильтра только для "главного" запроса. Как следствие, если ваше текущее условие не соответствует этому проверочному условию (например, если вы вызвали шаблон или цикл, который не является "главным" запросом), ваш фильтр не будет применён, и tax_query будет игнорироваться, что и приводит к отображению всех записей.

Решение

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

Вот пример улучшенного кода, который будет работать правильно:

function wc_filter_products($query) {
    if ( !is_admin() && $query->is_main_query() ) {
        // Проверка для страницы магазина WooCommerce
        if ( is_shop() || is_product_category() || is_product_tag() ) {
            $tax_query = array('relation' => 'AND');

            if ( !empty($_GET['make']) ) {
                $tax_query[] = array(
                    'taxonomy' => 'make',
                    'field' => 'slug',
                    'terms' => sanitize_text_field($_GET['make']),
                );
            }

            if ( !empty($_GET['city']) ) {
                $tax_query[] = array(
                    'taxonomy' => 'city',
                    'field' => 'slug',
                    'terms' => sanitize_text_field($_GET['city']),
                );
            }

            if ( !empty($_GET['year']) ) {
                $tax_query[] = array(
                    'taxonomy' => 'year',
                    'field' => 'slug',
                    'terms' => sanitize_text_field($_GET['year']),
                );
            }

            if ( !empty($_GET['color']) ) {
                $tax_query[] = array(
                    'taxonomy' => 'color',
                    'field' => 'slug',
                    'terms' => sanitize_text_field($_GET['color']),
                );
            }

            if ( !empty($tax_query) ) {
                $query->set('tax_query', $tax_query);
            }
        }
    }
}
add_action('pre_get_posts', 'wc_filter_products');

Что изменилось в коде:

  1. Учитываются только необходимые страницы: Я добавил проверку для страниц магазина, категорий и меток продуктов (is_shop(), is_product_category(), is_product_tag()). Это гарантирует, что ваш фильтр применится только тогда, когда это уместно.

  2. Сохранение чистоты запроса: Мы проверяем наличие полей из $_GET, и только если они есть, добавляем их в массив tax_query, что позволяет избежать лишних условий и ошибок.

Заключение

Некоторые страницы могут не быть "главным" запросом, но ваш код может требовать выполнения в определенных ситуациях. При таком подходе вы сможете избежать игнорирования логики фильтрации и без проблем отображать ваши кастомные запросы. Попробуйте применить предложенные изменения и протестировать, решена ли ваша проблема. Если возникнут новые вопросы или трудности, не стесняйтесь задавать их!

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

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