wp-kurs.ru wordpress WP-Kurs

Как использовать фильтр pre_get_posts для изменения запросов в WordPress

Что такое фильтр pre_get_posts и зачем он нужен

Фильтр pre_get_posts позволяет изменить основной WP_Query до выполнения запроса к базе данных. Это мощный инструмент для контроля вывода постов, например, на главной странице, в архивах, категориях или на страницах произвольных типов записей.

Часто возникает задача изменить количество записей, добавить фильтрацию по мета-данным или исключить определённые записи из выборки. Использование pre_get_posts — правильный способ сделать это, не нарушая логику WordPress и не меняя шаблоны.

Диагностика: как понять, что pre_get_posts работает неправильно

  • Изменения в запросе не применяются — выводятся стандартные записи без изменений.
  • Изменился не тот запрос — например, вы хотели изменить главную страницу, а изменился запрос в админке.
  • Появились ошибки или некорректный вывод данных.

Для диагностики полезно включить вывод SQL-запросов с помощью плагина Query Monitor или добавить отладочный вывод в код.

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

1. Проверка, что это основной запрос и фронтенд

function modify_main_query( $query ) {
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }
    // Дальше — условия для изменения запроса
}
add_action( 'pre_get_posts', 'modify_main_query' );

Обязательно проверяйте is_main_query(), иначе можно случайно поменять запросы в админке или второстепенные запросы, что приведёт к ошибкам.

2. Пример: изменить количество постов на главной странице

function change_posts_per_page_on_home( $query ) {
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }
    if ( $query->is_home() ) {
        $query->set( 'posts_per_page', 5 );
    }
}
add_action( 'pre_get_posts', 'change_posts_per_page_on_home' );

Этот код изменит число записей на главной странице с дефолтных 10 до 5.

3. Пример: исключить определённую категорию из архива

function exclude_category_from_archive( $query ) {
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }
    if ( $query->is_archive() ) {
        $query->set( 'cat', '-12' ); // исключаем категорию с ID 12
    }
}
add_action( 'pre_get_posts', 'exclude_category_from_archive' );

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

  • Откройте страницу, для которой меняли запрос (например, главную или архив).
  • Проверьте количество записей или наличие/отсутствие записей из исключённых категорий.
  • Для сложных изменений включите Query Monitor и посмотрите фактический SQL-запрос.

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

  • Не используется is_main_query(): приводит к изменениям в побочных запросах, могут сломаться виджеты или админка.
  • Изменение запроса в админке: добавляйте проверку is_admin(), чтобы код работал только на фронтенде.
  • Неправильные параметры запроса: например, ошибочный ID категории или опечатки в параметрах set(). Проверяйте значения и документацию WP_Query.

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

  • Не вызывайте тяжелые функции внутри pre_get_posts, чтобы не замедлять загрузку страниц.
  • Используйте точные условия (например, is_home(), is_archive()), чтобы не менять запросы без необходимости.
  • Кэшируйте результаты, если в запросе используются сложные условия мета-запросов.
  • Для больших сайтов с WooCommerce учитывайте совместимость с плагином. WooCommerce использует свои запросы, их можно отлавливать через $query->get('post_type') === 'product'.

Сравнение способов изменения запроса

МетодПлюсыМинусы
pre_get_postsГибко меняет запрос без изменения шаблонов, стандартизированный способНужно аккуратно использовать фильтры и проверки
Создание нового WP_QueryПолный контроль над запросом, изоляция от основногоНужно менять шаблоны, дублирование кода
Использование плагинов для изменения выводаБыстро, без кодаМеньше гибкости, возможны конфликты
×
Делай сайт лучше!!

-20% на премиум темы и плагины

Использовать скидку ⋙