Хук pre_get_posts — один из самых мощных и часто недооценённых инструментов в WordPress для изменения параметров основного и дополнительных запросов на сайте. Он позволяет динамично фильтровать выборку постов, изменять сортировку, ограничивать категории, настраивать пагинацию и многое другое без необходимости создавать отдельные запросы вручную.
Что такое хук pre_get_posts и зачем он нужен в WordPress
Хук pre_get_posts срабатывает в момент, когда WordPress формирует объект WP_Query, но ещё не выполняет SQL-запрос к базе. Это значит, что мы можем изменить параметры запроса, например, добавить условия для выборки постов, исключить определённые категории, изменить порядок сортировки или добавить мета-запросы.
Важный момент — этот хук вызывается для всех запросов, включая главный запрос (main query) и дополнительные (secondary queries). Поэтому при работе с ним нужно чётко проверять, с каким именно запросом мы имеем дело, чтобы не влиять на ненужные участки сайта.
Именно через pre_get_posts можно реализовать гибкие решения без создания собственных WP_Query, что улучшает производительность и упрощает поддержку кода.
Основы использования pre_get_posts: фильтрация главного запроса
Самый распространённый кейс — изменить главный запрос на странице блога, архива или главной. Например, ограничить вывод постов определённой категорией или изменить количество выводимых записей.
Пример функции, которая ограничивает главную страницу только постами из категории с ID 5:
function wpbono_pre_get_posts_main_query( $query ) {
if ( ! is_admin() && $query->is_main_query() && $query->is_home() ) {
// Выводим только посты из категории с ID 5
$query->set( 'cat', 5 );
// Устанавливаем количество постов на странице
$query->set( 'posts_per_page', 10 );
}
}
add_action( 'pre_get_posts', 'wpbono_pre_get_posts_main_query' );
Такая простая функция позволяет гибко управлять основным запросом без создания отдельного шаблона.
Проверка условий запроса
В примере выше используется несколько условий:
! is_admin()— чтобы действие не срабатывало в административной панели;$query->is_main_query()— чтобы менять только главный запрос;$query->is_home()— чтобы ограничить изменение только на главной странице блога.
Эти проверки обязательны, иначе можно случайно изменить запросы в админке или на других страницах.
Фильтрация архивов и кастомных типов записей через pre_get_posts
Еще один частый сценарий — изменить логику вывода на страницах архивов, например, для кастомных типов записей (Custom Post Types, CPT) или таксономий.
Допустим, у вас есть CPT portfolio, и вы хотите на архивной странице этого типа записей показывать только опубликованные элементы с определённой меткой.
function wpbono_pre_get_posts_portfolio( $query ) {
if ( ! is_admin() && $query->is_main_query() && is_post_type_archive( 'portfolio' ) ) {
// Показываем только опубликованные записи
$query->set( 'post_status', 'publish' );
// Добавим мета-запрос по ключу 'featured' = 'yes'
$meta_query = array(
array(
'key' => 'featured',
'value' => 'yes',
'compare' => '=',
),
);
$query->set( 'meta_query', $meta_query );
// Сортируем по дате публикации, сначала новые
$query->set( 'orderby', 'date' );
$query->set( 'order', 'DESC' );
}
}
add_action( 'pre_get_posts', 'wpbono_pre_get_posts_portfolio' );
Такой подход позволяет централизованно управлять выводом данных без изменения шаблонов.
Работа с таксономиями внутри pre_get_posts
Если нужно фильтровать посты по таксономии, например, показывать только записи с определённым тегом или категорией, это делается через параметр tax_query. Пример ограничения архива записей типа post категорией «Новости»:
function wpbono_pre_get_posts_news_category( $query ) {
if ( ! is_admin() && $query->is_main_query() && is_post_type_archive( 'post' ) ) {
$tax_query = array(
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => 'novosti',
),
);
$query->set( 'tax_query', $tax_query );
}
}
add_action( 'pre_get_posts', 'wpbono_pre_get_posts_news_category' );
Обратите внимание, что tax_query — это массив условий, которые объединяются по умолчанию через «AND».
Изменение запросов пагинации и AJAX-запросов через pre_get_posts
Иногда нужно подстроить запрос под пагинацию или под AJAX-запросы, например, в кастомных фильтрах или лайтбоксах.
Для этого важно учитывать параметры запроса, такие как paged — номер страницы пагинации. Вот пример, как настраивать пагинацию для кастомного запроса:
function wpbono_pre_get_posts_pagination( $query ) {
if ( ! is_admin() && $query->is_main_query() && is_archive() ) {
$paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
$query->set( 'posts_per_page', 8 );
$query->set( 'paged', $paged );
}
}
add_action( 'pre_get_posts', 'wpbono_pre_get_posts_pagination' );
Для AJAX-запросов, которые используют WP_Query, часто можно добавить дополнительный параметр запроса и при его наличии дополнять pre_get_posts нужной логикой. Например:
function wpbono_pre_get_posts_ajax_filter( $query ) {
if ( ! is_admin() && isset( $_GET['ajax_filter'] ) && $query->is_main_query() ) {
$query->set( 'meta_key', 'custom_field' );
$query->set( 'orderby', 'meta_value_num' );
$query->set( 'order', 'ASC' );
}
}
add_action( 'pre_get_posts', 'wpbono_pre_get_posts_ajax_filter' );
Практические советы по работе с pre_get_posts и популярные ошибки
При работе с pre_get_posts важно помнить несколько правил, которые помогут избежать проблем и конфликтов:
- Точно проверяйте условия запроса. Используйте
is_admin()>,is_main_query(),is_home(),is_archive()и другие условные теги, чтобы не затронуть лишние запросы. - Не создавайте бесконечные циклы. Внутри
pre_get_postsне запускайте новые WP_Query, чтобы не вызвать рекурсию. - Используйте параметры запроса, а не фильтры. Меняйте параметры запроса через
$query->set(), а не напрямую изменяйте SQL. - Тестируйте на разных страницах и сценариях. Разные шаблоны могут иметь свои особенности, поэтому важно проверять, что изменения не ломают логику сайта.
Если вы используете тему Bono от WPSHOP, то в ней уже предусмотрены корректные шаблоны для главного запроса, и pre_get_posts можно использовать для внесения изменений без правки шаблонов.
Заключение. Почему стоит использовать pre_get_posts в своих проектах
Хук pre_get_posts — это мощный и гибкий инструмент, который позволяет тонко настраивать вывод постов и кастомных типов записей в WordPress. Он помогает избежать дублирования запросов, упрощает поддержку кода и улучшает производительность сайта за счёт использования встроенных возможностей ядра.
Освоив pre_get_posts, вы сможете решать широкий спектр задач от фильтрации архивов до динамической сортировки и настройки пагинации. Это важный навык для любого разработчика, работающего с WordPress.