Что такое хук pre_get_posts и когда он нужен
Хук pre_get_posts позволяет изменять основной WP_Query ещё до запуска SQL-запроса. Это мощный инструмент для фильтрации и модификации списков записей (постов, товаров, кастомных типов) в любом месте сайта — на главной, архивных страницах, в админке или на фронтенде.
Чаще всего его используют, чтобы добавить условия фильтрации, изменить порядок вывода или ограничить типы записей без создания дополнительных запросов.
Диагностика: как понять, что нужен pre_get_posts
Если вы хотите:
- изменить набор записей в стандартных лупах WordPress;
- фильтровать архив категорий, тегов или кастомных таксономий;
- исключить или включить записи по метаполям, авторам, статусу;
- изменить порядок сортировки (orderby) для страниц блога или каталога WooCommerce;
то pre_get_posts — ваш выбор. Альтернативы вроде query_posts() или создания новых WP_Query не оптимальны и могут привести к ошибкам.
Пошаговое решение: пример фильтрации записей по метаполю
Предположим, нужно на странице архива постов вывести только те записи, у которых кастомное поле _my_custom_flag установлено в yes.
Добавьте следующий код в functions.php вашей темы или в плагин:
function filter_posts_by_custom_meta(\WP_Query $query) {
// Проверяем, что это главный запрос и фронтенд
if ( ! is_admin() && $query->is_main_query() && $query->is_archive() ) {
$meta_query = array(
array(
'key' => '_my_custom_flag',
'value' => 'yes',
'compare' => '=',
),
);
$query->set('meta_query', $meta_query);
}
}
add_action('pre_get_posts', 'filter_posts_by_custom_meta');Объяснение:
is_main_query()гарантирует, что меняется только основной запрос страницы;is_archive()ограничивает действие архивными страницами (можно заменить наis_home()для главной блога);- через
set('meta_query', ...)добавляется фильтр по метаполю.
Пример фильтрации WooCommerce товаров по атрибуту
Чтобы показать на странице магазина только товары с атрибутом pa_color равным red, используйте:
function filter_woocommerce_products_by_color(\WP_Query $query) {
if ( ! is_admin() && $query->is_main_query() && is_post_type_archive('product') ) {
$tax_query = array(
array(
'taxonomy' => 'pa_color',
'field' => 'slug',
'terms' => 'red',
),
);
$query->set('tax_query', $tax_query);
}
}
add_action('pre_get_posts', 'filter_woocommerce_products_by_color');Как проверить, что фильтрация работает
- Откройте соответствующую страницу (архив, магазин и т.п.)
- Убедитесь, что выводятся только записи/товары с нужными параметрами;
- Для отладки добавьте
var_dump($query->request)внутри функции, чтобы увидеть сгенерированный SQL-запрос; - Используйте плагин Query Monitor для анализа запросов WP_Query.
Частые ошибки при работе с pre_get_posts
- Не проверяете is_main_query() — меняется не только основной запрос, из-за чего страница может отобразиться некорректно.
- Отсутствует условие is_admin() — изменение запросов в админке приводит к сбоям.
- Неправильное использование условий типа is_archive(), is_home(), is_post_type_archive() — фильтр не сработает на нужной странице.
- Перезаписываете существующий meta_query или tax_query без объединения, из-за чего теряются другие фильтры.
Практические советы по безопасности и производительности
- Не добавляйте тяжелые JOIN или сложные запросы в
pre_get_postsбез оптимизации — это замедлит загрузку страницы. - Используйте кеширование (например, Object Cache) для повторных запросов с фильтрами.
- Для сложных условий объединяйте фильтры через
$query->set('meta_query', array_merge($existing_meta_query, $new_meta_query)), чтобы не терять данные. - Тестируйте влияние фильтра на разные страницы сайта.
Сравнение вариантов фильтрации записей
| Метод | Плюсы | Минусы |
|---|---|---|
| pre_get_posts | Изменяет основной запрос без создания нового; оптимально для изменения архивов и главной; | Требует аккуратности с условиями; может влиять на производительность при сложных запросах; |
| query_posts() | Простой вызов для изменения запроса; | Перезаписывает глобальный запрос, вызывает баги и проблемы с пагинацией; |
| WP_Query новый объект | Гибкий, не влияет на основной запрос; | Нужно вручную выводить результаты и управлять пагинацией; |