Диагностика задачи: зачем нужна динамическая фильтрация постов через pre_get_posts
Часто в проектах на WordPress возникает необходимость изменить стандартный запрос постов без создания нового WP_Query. Это полезно, если нужно фильтровать посты в основном цикле, на страницах архива, категории, или в любом другом месте, где WordPress выводит посты автоматически. Хук pre_get_posts позволяет модифицировать параметры запроса до выполнения, меняя условия выборки постов.
Пример задачи: показать на главной странице только посты из определённой категории или с мета-полем, а на страницах категорий — фильтровать по дополнительным условиям. Без pre_get_posts пришлось бы создавать отдельные запросы и изменять шаблоны, что неудобно и плохо для SEO.
Как правильно использовать хук pre_get_posts для фильтрации
Основы работы с pre_get_posts
Хук вызывается перед выполнением основного запроса WP_Query. В функции-обработчике можно получить объект запроса и изменить его параметры — например, set('category_name', 'news') или set('meta_key', 'featured').
add_action('pre_get_posts', 'custom_filter_main_query');
function custom_filter_main_query(\WP_Query $query) {
// Изменяем только главный запрос и фронтенд
if ( !is_admin() && $query->is_main_query() ) {
if ( is_home() ) {
// Показываем только посты из категории news
$query->set('category_name', 'news');
// Можно добавить дополнительные параметры
$query->set('posts_per_page', 5);
}
}
}Фильтрация по произвольным мета-данным
Для более сложных условий можно использовать параметр meta_query. Например, отфильтровать посты с мета-полем featured равным 1:
add_action('pre_get_posts', 'filter_featured_posts');
function filter_featured_posts($query) {
if (!is_admin() && $query->is_main_query() && is_home()) {
$meta_query = array(
array(
'key' => 'featured',
'value' => '1',
'compare' => '=',
),
);
$query->set('meta_query', $meta_query);
}
}Пошаговое решение: как внедрить динамическую фильтрацию через pre_get_posts
- Откройте файл
functions.phpвашей темы (лучше дочерней темы). - Добавьте функцию-обработчик, проверяющую
is_main_query()и!is_admin(), чтобы не влиять на админку и второстепенные запросы. - В зависимости от условий (например,
is_home(),is_category()) измените параметры запроса через$query->set(). - Используйте
meta_query,tax_queryили другие параметры WP_Query для точной фильтрации. - Сохраните файл и протестируйте на фронтенде.
Проверка результата после внедрения
Чтобы проверить, что фильтрация сработала:
- Перейдите на страницу, где применён фильтр (например, главная страница).
- Убедитесь, что выводятся только нужные посты (например, только из категории news или с нужным мета-полем).
- Включите отладку запросов, добавив в
functions.php:
add_action('wp_footer', function() {
global $wp_query;
echo '<pre>' . esc_html(print_r($wp_query->request, true)) . '</pre>';
});Это выведет SQL-запрос, по которому WordPress получает посты. Проверьте, что в запросе присутствуют нужные условия (например, WHERE по категории или мета-полю).
Частые ошибки при работе с pre_get_posts и как их исправить
- Изменение не основного запроса: если не проверять
$query->is_main_query(), фильтрация может применяться к админке или к дополнительным WP_Query, что приведёт к ошибкам. Решение: всегда проверяйтеis_main_query()и!is_admin(). - Конфликт условий: если несколько функций меняют запрос без проверки условий, они могут конфликтовать. Решение: объединяйте логику в одной функции или используйте приоритеты в хуках.
- Неправильные параметры запроса: например, неправильный ключ или значение в
meta_query. Решение: внимательно проверяйте документацию WP_Query и используйте отладку SQL. - Отсутствие проверки контекста: изменение запроса на всех страницах вместо только нужных. Решение: используйте условные теги (например,
is_home(),is_category()).
Практические советы по производительности и безопасности
- Фильтрация через
pre_get_postsне требует дополнительных запросов — это эффективно. - Старайтесь минимизировать сложные
meta_query, особенно сLIKE, чтобы не замедлять выборку. - Кэшируйте результаты на уровне объекта (Object Cache) или внешних системах, если фильтрация сложная.
- Не выводите отладочные SQL-запросы на продакшн-сайте — это может раскрыть структуру базы.
Сравнение способов фильтрации постов
| Метод | Плюсы | Минусы |
|---|---|---|
| pre_get_posts | Изменяет основной запрос без дополнительного WP_Query, SEO-дружественно, легко интегрируется | Можно случайно повлиять на нежелательные запросы без проверки |
| Создание собственного WP_Query | Полный контроль, можно использовать в любом месте шаблона | Дублирование запросов, возможные проблемы с пагинацией и SEO |
| Плагины для фильтрации (например, FacetWP) | Удобный UI, готовые решения, Ajax-поддержка | Нагрузка на сайт, лишний вес, зависимость от сторонних разработчиков |