Pre_get_posts — Событие срабатывает перед каждым запросом WP_Query. До того, как был сделан запрос в базу. Используется для изменения запроса. Хук-событие WordPress
Опубликовано: 01.09.2018
Событие срабатывает перед каждым запросом WP_Query. До того, как был сделан запрос в базу. Используется для изменения запроса.
Событие pre_get_posts дает возможность изменять объект $wp_query, потому что объект передается в хук по ссылке (&), это означает, что любые действия над $query внутри функции буду влиять на основной объект $wp_query. Для этого хука не надо возвращать никаких данных.
ВАЖНО! pre_get_posts срабатывает для каждого запроса WP_Query: основной запрос, дополнительный запрос, запрос в админ-панели, запросы в виджетах и т.д.
Поэтому нужно убедитесь, что вы изменяете именно нужны вам запрос, для этого перед изменением запроса используйте всевозможные Условные теги , чтобы точно ограничить изменение (см. примеры).
Часто используемые функции внутри хука pre_get_posts:
Использование
add_action( 'pre_get_posts', 'action_function_name_11' ); function action_function_name_11( $query ) { // Действия... }Параметры
$query(объект) Объект WP_Query.Заметки
Аргумент передается по ссылке
Объект $query предается по ссылке, поэтому нет необходимости определять глобальную переменную. Любые изменения $query внутри функции влияют сразу на оригинальный объект.
Запросы постоянных страниц
pre_get_posts нельзя использовать для изменения запросов связанных с постоянными страницами, потому что 'is_page', 'is_singular', 'pagename' и другие параметры (зависимые к ЧПУ) уже установлены в объекте. Рекомендуется использовать new WP_Query в шаблоне постоянной страницы, чтобы изменить запрос.
Определение нужного запроса
При использовании pre_get_posts, нужно точно определить, в какой конкретно запрос вы вносите изменения. Полезный метод для этого: $query->is_main_query() - он поможет вам убедиться, что вносимые изменения будут влиять только на основные запросы. Используйте его в связке с условными тегами . Чтобы изменять запрос только для страниц, которые вам нужны.
Например, мы хотим изменить запрос на странице категорий и не делаем проверку is_category(), тогда наши изменения будут влиять на формирования запроса в админ-панели, на других страницах сайта и где угодно еще. Поэтому четко определяйте, для какого запроса вы вносите изменения через действие-хук pre_get_posts.
Использование в админ-панели
Этот фильтр можно также использовать для изменения запросов в админ-панели. В таких случаях, убедитесь что внесенные изменения будут работать на странице вывода записей. Например, проверка $query->is_main_query() и is_post_type_archive('movie') (изменяем запрос для лицевой части для записей типа movie), изменит также запрос на страницы edit.php?post_type=movie. Чтобы этого не произошло, нужно использовать еще проверку ! is_admin().
Внимание! Условные теги
pre_get_posts срабатывает до того, как объект WP_Query полностью определится. Поэтому некоторые условные теги, опирающиеся на данные WP_Query еще не работают. Например, is_front_page() не работает, тогда как is_home() будет работать. Поэтому вам лучше работать с данными объекта напрямую, например: $query->is_search.
Весь список свойств которые можно использовать вместо условного тега:
$query->is_404 $query->is_admin $query->is_archive $query->is_attachment $query->is_author $query->is_category $query->is_comments_popup $query->is_comment_feed $query->is_date $query->is_day $query->is_feed $query->is_home $query->is_month $query->is_page $query->is_paged $query->is_posts_page $query->is_post_type_archive $query->is_preview $query->is_robots $query->is_search $query->is_single $query->is_singular $query->is_tag $query->is_tax $query->is_time $query->is_trackback $query->is_year // функции $query->is_front_page() $query->is_main_query()Все остальные условные теги нужно заменить проверкой или методом класса. Например, is_front_page(), нужно заменить на такую проверку:
if( $query->is_home || ($query->get('page_id') == get_option('page_on_front')) ){ // это front_page }или такой метод:
if( $query->is_front_page() ){ // это front_page }is_main_query() не рекомендуется использовать внутри этого хука. Нужно отдать предпочтение методу $query->is_main_query().
Отступы и пагинация
Использование аргумента offset в любом запросе может сломать пагинацию. Поэтому, если вы используете offset, то вам нужно изменить запрос для всех страниц пагинации, опираясь на первоначальный отступ (offset). Подробнее об этом я писал в этой статье: Как использовать параметр offset не ломая пагинацию .
Примеры
#1 Исключение категорий на главной
Этот пример показывает как убрать посты из указанных категорий из вывода на главной странице блога. Например, у нас есть 2 категории с ID 1 и 1347, которые нам не нужно показывать на главной. Чтобы исключить эти категории из запроса, используйте такой код в плагине или в теме:
function exclude_category( $query ) { if ( $query->is_front_page() && $query->is_main_query() ) { $query->set( 'cat', '-1,-1347' ); } } add_action( 'pre_get_posts', 'exclude_category' );#2 Исключение постоянных страниц из результатов поиска
Когда пользователи вашего сайта ищут что-либо, часто в результатах поиска могут попадаться постоянные страницы, которые в принципе совсем не нужны в результатах поиска, и которые можно исключить из поиска насовсем. Используйте хук pre_get_posts, чтобы исключить из результатов поиска постоянных страницы:
function search_filter($query) { if ( ! is_admin() && $query->is_main_query() ) { if ($query->is_search) { $query->set('post_type', 'post'); } } } add_action( 'pre_get_posts', 'search_filter' );#3 Включение произвольного типа записей в результаты поиска
Включать в поиск произвольный тип записи или нет, устанавливается при регистрации типа записи, в аргументах функции register_post_type() : аргумент public=true добавляет в результат поиска произвольный тип записи.
Если, произвольный тип не включен в поиск, но нужно чтобы он участвовал в поиске, то используйте такой код, аналог предыдущего:
add_action('pre_get_posts', 'get_posts_search_filter'); function get_posts_search_filter( $query ){ if ( ! is_admin() && $query->is_main_query() && $query->is_search ) { $query->set('post_type', array('post', 'movie') ); } }#4 Изменение количества выводимых на странице постов
В WordPress есть глобальная настройка, которая учитывает сколько записей показывать на странице - posts_per_page. Лучше всего изменять этот параметр до основного запроса, в целях экономии ресурсов, чтобы не делать повторных запрос. Так, мы можем использовать хук-действие pre_get_posts, чтобы изменить количество выводимых записей на странице.
Этот пример, показывает как перезаписать параметр posts_per_page для страницы архивов произвольного типа записи movie:
add_action('pre_get_posts', 'hwl_home_pagesize', 1 ); function hwl_home_pagesize( $query ) { // Выходим, если это админ-панель или не основной запрос. if( is_admin() || ! $query->is_main_query() ) return; if( is_home() ){ // Выводим только 1 пост на главной странице $query->set( 'posts_per_page', 1 ); } if( $query->is_post_type_archive('movie') ){ // Выводим 50 записей если это архив типа записи 'movie' $query->set( 'posts_per_page', 50 ); } }Пример объекта WP_Query
Для того, чтобы быстро разобраться как и что использовать, ниже пример объекта WP_Query (global $wp_query), который передается в хук по ссылке (&$query):
WP_Query Object ( [query_vars] => Array ( [page] => 0 [pagename] => s [error] => [m] => [p] => 0 [post_parent] => [subpost] => [subpost_id] => [attachment] => [attachment_id] => 0 [name] => s [static] => [page_id] => 0 [second] => [minute] => [hour] => [day] => 0 [monthnum] => 0 [year] => 0 [w] => 0 [category_name] => [tag] => [cat] => [tag_id] => [author] => [author_name] => [feed] => [tb] => [paged] => 0 [comments_popup] => [meta_key] => [meta_value] => [preview] => [s] => [sentence] => [fields] => [menu_order] => [category__in] => Array ( ) [category__not_in] => Array ( ) [category__and] => Array ( ) [post__in] => Array ( ) [post__not_in] => Array ( ) [tag__in] => Array ( ) [tag__not_in] => Array ( ) [tag__and] => Array ( ) [tag_slug__in] => Array ( ) [tag_slug__and] => Array ( ) [post_parent__in] => Array ( ) [post_parent__not_in] => Array ( ) [author__in] => Array ( ) [author__not_in] => Array ( ) [ignore_sticky_posts] => [suppress_filters] => [cache_results] => [update_post_term_cache] => 1 [update_post_meta_cache] => 1 [post_type] => [posts_per_page] => 10 [nopaging] => [comments_per_page] => 10 [no_found_rows] => [order] => DESC ) [tax_query] => [meta_query] => WP_Meta_Query Object ( [queries] => Array ( ) [relation] => ) [date_query] => [post_count] => 1 [current_post] => -1 [in_the_loop] => [comment_count] => 0 [current_comment] => -1 [found_posts] => 1 [max_num_pages] => 0 [max_num_comment_pages] => 0 [is_single] => [is_preview] => [is_page] => 1 [is_archive] => [is_date] => [is_year] => [is_month] => [is_day] => [is_time] => [is_author] => [is_category] => [is_tag] => [is_tax] => [is_search] => [is_feed] => [is_comment_feed] => [is_trackback] => [is_home] => [is_404] => [is_comments_popup] => [is_paged] => [is_admin] => [is_attachment] => [is_singular] => 1 [is_robots] => [is_posts_page] => [is_post_type_archive] => [query_vars_hash] => c248b13e251e8fba33892e0bd7a5bd98 [query_vars_changed] => [thumbnails_cached] => [stopwords:WP_Query:private] => [query] => Array ( [page] => [pagename] => s ) [queried_object] => WP_Post Object ( [ID] => 19 [post_author] => 1 [post_date] => 2010-04-01 20:09:20 [post_date_gmt] => 2010-04-01 16:09:20 [post_content] => [post_title] => Страница для исполнения [post_excerpt] => [post_status] => private [comment_status] => open [ping_status] => closed [post_password] => [post_name] => s [to_ping] => [pinged] => [post_modified] => 2011-04-25 17:44:42 [post_modified_gmt] => 2011-04-25 13:44:42 [post_content_filtered] => [post_parent] => 0 [guid] => http://site.ru/s [menu_order] => 0 [post_type] => page [post_mime_type] => [comment_count] => 0 [filter] => raw ) [queried_object_id] => 19 [request] => SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND (wp_posts.ID = '19') AND wp_posts.post_type = 'page' ORDER BY wp_posts.post_date DESC [posts] => Array ( [0] => WP_Post Object ( [ID] => 19 [post_author] => 1 [post_date] => 2010-04-01 20:09:20 [post_date_gmt] => 2010-04-01 16:09:20 [post_content] => [post_title] => Страница для исполнения [post_excerpt] => [post_status] => private [comment_status] => open [ping_status] => closed [post_password] => [post_name] => s [to_ping] => [pinged] => [post_modified] => 2011-04-25 17:44:42 [post_modified_gmt] => 2011-04-25 13:44:42 [post_content_filtered] => [post_parent] => 0 [guid] => http://site.ru/s [menu_order] => 0 [post_type] => page [post_mime_type] => [comment_count] => 0 [filter] => raw ) ) [post] => WP_Post Object ( [ID] => 19 [post_author] => 1 [post_date] => 2010-04-01 20:09:20 [post_date_gmt] => 2010-04-01 16:09:20 [post_content] => [post_title] => Страница для исполнения [post_excerpt] => [post_status] => private [comment_status] => open [ping_status] => closed [post_password] => [post_name] => s [to_ping] => [pinged] => [post_modified] => 2011-04-25 17:44:42 [post_modified_gmt] => 2011-04-25 13:44:42 [post_content_filtered] => [post_parent] => 0 [guid] => http://site.ru/s [menu_order] => 0 [post_type] => page [post_mime_type] => [comment_count] => 0 [filter] => raw ) )