Что такое хук pre_get_posts и зачем он нужен
Хук pre_get_posts позволяет изменить параметры основного запроса WordPress перед его выполнением. Это ключевой инструмент для тонкой настройки выборки постов, категорий, товаров WooCommerce и других типов записей без создания новых запросов.
Когда использовать pre_get_posts
- Изменить количество постов на главной странице или в архиве;
- Фильтровать товары WooCommerce по метаполям или атрибутам;
- Исключить определённые категории из ленты;
- Добавить кастомные параметры к запросу без изменения шаблонов.
Диагностика проблем с pre_get_posts
Частая ошибка — неправильно определить, какой запрос изменять. Основной запрос и дополнительные WP_Query обрабатываются одинаково через этот хук. Если изменить не тот запрос, результат не будет соответствовать ожиданиям или страница сломается.
Чтобы проверить, какой запрос обрабатывается, используйте условные теги и метод is_main_query(). Пример диагностики:
add_action('pre_get_posts', function($query) {
if ($query->is_main_query()) {
error_log('Основной запрос на странице: ' . (is_home() ? 'Главная' : 'Другая'));
}
});
Если нет нужного результата, значит вы меняете не основной запрос.
Пошаговое решение: фильтрация товаров WooCommerce по произвольному полю
Задача: показать на архиве товаров только те продукты, у которых метаполе _custom_label содержит значение new-arrival.
1. Подключаем хук pre_get_posts в functions.php или в плагине:
add_action('pre_get_posts', 'filter_woocommerce_products_by_custom_meta');
function filter_woocommerce_products_by_custom_meta($query) {
// Проверить, что это фронтенд, архив товаров и основной запрос
if (!is_admin() && $query->is_main_query() && is_post_type_archive('product')) {
$meta_query = array(
array(
'key' => '_custom_label',
'value' => 'new-arrival',
'compare' => '='
)
);
$query->set('meta_query', $meta_query);
}
}
2. Очистить кэш сайта и браузера.
3. Обновить страницу архива товаров.
Как проверить, что фильтр сработал
Самый простой способ — добавить в запрос дополнительное условие, которое меняет количество товаров. Например, добавьте в meta_query условие, которое убирает все товары:
$query->set('posts_per_page', 1);
Если на сайте отображается ровно один товар, значит ваш фильтр применяется. Также можно посмотреть SQL-запросы через плагин Query Monitor или вставить в код:
add_action('pre_get_posts', function($query) {
if (!is_admin() && $query->is_main_query() && is_post_type_archive('product')) {
error_log($query->request); // Покажет SQL-запрос в логе
}
});
Частые ошибки при использовании pre_get_posts
- Изменение не основного запроса: не использовать
$query->is_main_query()ведёт к неожиданным результатам на странице. - Отсутствие проверки фронтенда: изменение запросов в админке может привести к ошибкам.
- Перезапись meta_query без объединения: если в запрос уже есть meta_query, нужно объединять его с новым, иначе теряются условия.
- Неочищенный кэш: изменения не видны из-за кэширования.
Как правильно объединить несколько meta_query
Если нужно добавить условие, но не потерять существующие, используйте такой подход:
add_action('pre_get_posts', 'add_meta_query_condition');
function add_meta_query_condition($query) {
if (!is_admin() && $query->is_main_query() && is_post_type_archive('product')) {
$existing = $query->get('meta_query');
if (!is_array($existing)) {
$existing = array();
}
$existing[] = array(
'key' => '_custom_label',
'value' => 'new-arrival',
'compare' => '='
);
$query->set('meta_query', $existing);
}
}
Практические советы по безопасности и производительности
- Не используйте
pre_get_postsдля сложных фильтров с большим количеством условий — лучше создайте отдельный WP_Query. - Добавляйте индексы в базу данных на метаполя, которые часто используете в
meta_query(особенно для WooCommerce). - Проверяйте, что ваши условия не создают слишком тяжёлые SQL-запросы, чтобы избежать замедления.
- Используйте кэширование запросов (например, Object Cache) для часто повторяющихся условий.
Сравнение способов фильтрации запросов WordPress
| Метод | Плюсы | Минусы |
|---|---|---|
| pre_get_posts | Изменяет основной запрос без дополнительного кода шаблона; работает для любых страниц | Можно случайно изменить не тот запрос; нельзя использовать для сложных запросов |
| Создание нового WP_Query | Максимальная гибкость; можно получить любые данные | Нужно вручную выводить результаты; дублирование кода |
| Использование плагинов фильтрации | Простота настройки; много готовых функций | Избыточность кода; может замедлять сайт; зависимость от обновлений |