Как использовать хук pre_get_posts для фильтрации записей в WordPress

Диагностика: почему стандартные запросы не подходят для сложной фильтрации

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

Для решения таких задач существует хук pre_get_posts, который позволяет изменять объект запроса до его выполнения. Однако неправильное использование этого хука может привести к проблемам, таким как изменение запросов в админке или на страницах, где этого не нужно.

Пошаговое решение: корректное применение pre_get_posts

1. Определяем, где нужно изменить запрос

Чтобы избежать влияния на админ-панель и другие запросы, обязательно проверяем параметры запроса:

function my_custom_filter( $query ) {
    // Проверяем, что это основной запрос и не админка
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }
    
    // Пример: изменить запрос только на главной странице
    if ( $query->is_home() ) {
        // Добавляем условие фильтрации
    }
}
add_action( 'pre_get_posts', 'my_custom_filter' );

2. Добавляем условия фильтрации

Например, исключим из главной страницы записи из категории с ID 5 и добавим мета-запрос, чтобы выводить только опубликованные товары с метаполем in_stock равным 1.

function my_custom_filter( $query ) {
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }

    if ( $query->is_home() ) {
        // Исключаем категорию с ID 5
        $query->set( 'cat', '-5' );

        // Добавляем мета-запрос
        $meta_query = array(
            array(
                'key' => 'in_stock',
                'value' => '1',
                'compare' => '=',
            ),
        );
        $query->set( 'meta_query', $meta_query );
    }
}
add_action( 'pre_get_posts', 'my_custom_filter' );

3. Обработка кастомных типов записей и таксономий

Если нужно фильтровать архив кастомного типа записей или таксономии, проверяем соответствующие условные теги и меняем параметры:

function my_custom_post_type_filter( $query ) {
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }

    if ( $query->is_post_type_archive( 'product' ) ) {
        // Выводим только опубликованные товары с ценой больше 1000
        $meta_query = array(
            array(
                'key' => 'price',
                'value' => 1000,
                'compare' => '>',
                'type' => 'NUMERIC',
            ),
        );
        $query->set( 'meta_query', $meta_query );
    }
}
add_action( 'pre_get_posts', 'my_custom_post_type_filter' );

Проверка результата после внедрения

  • Очистите кеш сайта и браузера, чтобы изменения запроса вступили в силу.
  • Откройте фронтенд страницы, где вы изменяли запрос (например, главную или архив кастомного типа).
  • Проверьте, что записи отфильтрованы согласно заданным условиям (например, отсутствуют записи из исключённой категории или отображаются товары с метаполем in_stock = 1).
  • Для детальной отладки можно временно добавить вывод SQL-запроса:
add_action( 'pre_get_posts', function( $query ) {
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }
    // Ваша логика

    add_filter( 'posts_request', function( $sql ) {
        error_log( $sql ); // Запишет запрос в error_log
        return $sql;
    } );
} );

Частые ошибки и как их исправить

  • Изменение запросов в админке: забыли проверить is_admin(), из-за чего ломаются запросы в административной панели. Решение: всегда добавляйте проверку if ( is_admin() ) return;.
  • Не проверяется основной запрос: изменения применяются ко всем WP_Query, включая вложенные запросы (например, в виджетах). Решение: используйте $query->is_main_query() для попадания только в главный запрос.
  • Неправильный синтаксис мета-запросов: не указываете тип данных или используете неправильный ключ. Решение: всегда задавайте type в мета-запросах, особенно для чисел.

Практические советы по безопасности и производительности

  • Не используйте pre_get_posts для сложных выборок с большими мета-запросами без индексации — это сильно нагружает базу данных.
  • При необходимости кэшируйте результаты запросов с помощью Transients API или плагинов кеширования.
  • Избегайте дублирования логики фильтрации в шаблонах и хуках — централизуйте её в pre_get_posts.

Сравнение способов фильтрации записей

МетодПлюсыМинусы
Использование pre_get_postsГибкая фильтрация, применяется до выполнения запроса, не требует кастомных запросов в шаблонахТребует аккуратности, можно сломать админку без проверок
Создание кастомного WP_Query в шаблонеЛокальный контроль над выборкой, меньше риска повлиять на другие части сайтаДублирование кода, хуже поддерживаемость
Использование плагинов фильтрацииУпрощение для неразработчиков, готовые интерфейсыМожет быть перегружено, меньше гибкости, влияет на производительность
Автоматическое сохранение и обновление мета-полей при изменении записи в WordPress
19.12.2025
Обновление WordPress без потери настроек и данных
07.01.2026
Оптимальное создание и использование WP-Cron в WordPress
14.03.2026
WooCommerce: автоматическое удаление неактивных пользователей с заказами
14.07.2026
Как создать собственный тип записей в WordPress с примерами кода
30.11.2025