Что такое хук pre_get_posts и зачем он нужен
Хук pre_get_posts позволяет изменять параметры основного запроса WordPress до его выполнения. Это мощный инструмент для точечной фильтрации выборки постов на страницах сайта — будь то главная страница, архивы, поисковые результаты или кастомные шаблоны. В отличие от фильтрации выборки через WP_Query в шаблонах, использование pre_get_posts позволяет централизованно и эффективно модифицировать запросы без дублирования кода.
Диагностика: как проверить, что запрос можно изменить через pre_get_posts
Для начала нужно убедиться, что вы изменяете именно главный запрос, иначе можно случайно повлиять на лишние запросы (например, виджеты или дополнительные WP_Query). Для этого в функции обработчике используйте проверку:
function my_pre_get_posts_handler( \WP_Query $query ) {
if ( ! $query->is_main_query() ) {
return;
}
if ( is_admin() ) {
return;
}
// Ваш код...
}
add_action( 'pre_get_posts', 'my_pre_get_posts_handler' );Эти проверки гарантируют, что изменения будут применяться только к основному запросу на фронтенде.
Пошаговое решение: фильтрация постов по произвольному условию
Рассмотрим конкретный сценарий: нужно исключить из главной страницы посты определённой категории (например, ID категории 15). Вот рабочий пример кода в functions.php темы или плагине:
function exclude_category_from_home( \WP_Query $query ) {
if ( ! $query->is_main_query() || is_admin() ) {
return;
}
if ( $query->is_home() ) {
// Исключаем категорию с ID 15
$query->set( 'cat', '-15' );
}
}
add_action( 'pre_get_posts', 'exclude_category_from_home' );Объяснение:
- is_home() — условие для главной страницы блога;
- 'cat' => '-15' означает исключение категории с ID 15 из выборки.
Фильтрация по метаполям
Допустим, нужно вывести только посты с метаполем featured равным yes. Используем параметр meta_query:
function filter_posts_by_meta( \WP_Query $query ) {
if ( ! $query->is_main_query() || is_admin() ) {
return;
}
if ( is_archive() ) {
$meta_query = array(
array(
'key' => 'featured',
'value' => 'yes',
'compare' => '='
)
);
$query->set( 'meta_query', $meta_query );
}
}
add_action( 'pre_get_posts', 'filter_posts_by_meta' );Проверка результата после внедрения
- Откройте фронтенд сайта на странице, где применена фильтрация (главная, архив или другая).
- Проверьте, что посты, которые должны быть исключены, действительно отсутствуют.
- Для метафильтрации убедитесь, что посты с нужным метазначением отображаются, а остальные — нет.
- Включите WP_DEBUG в
wp-config.php, чтобы убедиться в отсутствии ошибок PHP. - Вызовите
var_dump($query->query_vars)в обработчике (только для теста), чтобы увидеть параметры запроса.
Частые ошибки и как их исправить
- Изменения влияют на админку: не забывайте проверять
is_admin(), иначе фильтрация может сломать админские запросы. - Изменение не применяется: убедитесь, что
is_main_query()возвращает true, иначе вы редактируете не тот запрос. - Неправильные параметры запроса: используйте правильные ключи и значения в
set(), например,'cat' => '-15'для исключения категории. - Конфликты с плагинами: некоторые плагины жестко задают параметры запроса, в таких случаях фильтрация через
pre_get_postsможет не сработать.
Практические советы по безопасности и производительности
- Не выполняйте сложные или ресурсоёмкие операции внутри обработчика
pre_get_posts, так как он срабатывает при каждом запросе. - Для сложных фильтров используйте кэширование результатов запросов, например, через Transient API.
- При фильтрации по метаполям добавьте индексы в таблицу
wp_postmeta, если это возможно, для ускорения запросов. - Не делайте фильтрацию на страницах, где это не нужно — всегда ограничивайте условиями (например,
is_home(),is_archive()).
Сравнение методов фильтрации постов
| Метод | Плюсы | Минусы | Когда использовать |
|---|---|---|---|
pre_get_posts | Централизованное управление, эффективное изменение главного запроса | Может влиять на все запросы, если не фильтровать правильно | Фильтрация постов на уровне основного запроса |
| WP_Query в шаблоне | Локальное переопределение выборки | Дублирование кода, сложность поддержки | Вывод дополнительного списка постов |
| Фильтрация после выборки (PHP) | Гибкость в обработке | Нагрузка на сервер, медленнее | Редкие случаи, когда нельзя изменить запрос |