pre_get_posts
Дозволяє змінити запит WP_Query . Спрацьовує перед запитом.
Ця подія дозволяє змінювати об’єкт $wp_query. Об’єкт передається в хук за посиланням – це означає, що будь-які дії над змінною $query всередині функції впливатимуть на основний об’єкт WP_Query . Для цього хука не треба повертати жодних даних.
ВАЖЛИВО! Ця подія спрацьовує для кожного запиту WP_Query:
- основний запит
- додатковий запит
- запит до адмін-панелі
- запити у віджетах
- і т.д.
Тому переконайтеся, що змінюєте саме потрібний запит, для цього перед зміною запиту використовуйте всілякі Умовні теги , щоб точно обмежити зміну (див. приклади).
Часті функції всередині цього хука:
- $query->is_main_query() — змінимо лише основний запит WP.
- is_admin() — змінимо запити лише до адмін панелі.
- get_queried_object() – дані поточного запиту (поточної сторінки).
Використання get_queried_object() всередині цього хука, потрібно здійснювати перевіркою $query->is_author :
add_action( 'pre_get_posts', 'function_name'); function function_name( $query ){ if( $query->is_author ) $qo = $query->queried_object(); else $qo = get_queried_object(); }
Схоже, що це баг при якому для сторінки автора занадто рано використовувати get_queried_object() до обробки даних запиту. Саме при обробці встановлюється властивість $wp_query->query_vars[‘author’] на основі якого встановлюється об’єкт користувача на сторінці користувача функції get_queried_object() . А якщо цих даних немає, то і поточний об’єкт користувача отримати не вдасться.
Створив тикет за цим багом: https://core.trac.wordpress.org/ticket/51829
Використання
add_action( 'pre_get_posts', 'wp_kama_pre_get_posts_action'); /** * Function for `pre_get_posts` action-hook. * * @param WP_Query $query WP_Query instance (passed by reference). * * @return void */ function wp_kama_pre_get_posts_action( $query ){ // action... }
-
$query
( WP_Query ) - Об’єкт WP_Query.
нотатки
Аргумент передається за посиланням
Об’єкт $query надається за посиланням, тому немає необхідності визначати глобальну змінну. Будь-які зміни $query усередині функції впливають відразу на оригінальний об’єкт.
Запити постійних сторінок
pre_get_posts не можна використовувати для зміни запитів, пов’язаних із постійними сторінками, тому що ‘is_page’, ‘is_singular’, ‘pagename’ та інші параметри (залежні до ЧПК) вже встановлені в об’єкті. Рекомендовано використовувати новий WP_Query у шаблоні постійної сторінки, щоб змінити запит.
Визначення потрібного запиту
При використанні pre_get_posts потрібно точно визначити, в який конкретно запит ви вносите зміни. Корисний метод для цього: умовними тегами . Щоб змінювати запит лише для сторінок, які вам потрібні.
Наприклад, ми хочемо змінити запит на сторінці категорій і не робимо перевірку is_category() , тоді наші зміни впливатимуть на формування запиту в адмін-панелі, на інших сторінках сайту та будь-де. Тому чітко визначайте, для якого запиту ви вносите зміни через дію-хук pre_get_posts .
Використання в адмін-панелі
Цю подію можна також використовувати для зміни запитів до адмін-панелі. У таких випадках переконайтеся, що внесені зміни працюватимуть на сторінці виводу записів. Наприклад, перевірка is_post_type_archive(‘movie’) (змінюємо запит для лицьової частини для записів типу movie), змінить також запит на сторінки edit.php?post_type=movie
. Щоб цього не сталося, потрібно використати ще перевірку ! is_admin()
.
Увага! Умовні теги
Ця подія спрацьовує до того, як об’єкт WP_Query повністю визначиться. Тому деякі умовні теги, що спираються на дані WP_Query, ще не працюють. Наприклад, 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_front_page() ){ // це front_page }
або на таку перевірку:
if( $query->is_home || ( $query->get('page_id') == get_option('page_on_front') ) ) { // це front_page }
Відступи та пагінація
Використання аргументу offset
у будь-якому запиті може зламати пагінацію. Тому, якщо ви використовуєте offset, вам потрібно змінити запит для всіх сторінок пагінації, спираючись на початковий відступ (offset). Докладніше про це я писав у цій статті: Як використовувати параметр offset не ламаючи пагінацію .
Приклади
#1 Включення довільного типу записів до результатів пошуку
Включати пошук довільний тип запису чи ні, встановлюється при реєстрації типу запису, в аргументах функції 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', [ 'post', 'movie' ] ); } }
#2 Виняток категорій на головній
Цей приклад показує, як прибрати пости із зазначених категорій з висновку на головній сторінці блогу. Наприклад, у нас є 2 категорії з ID 1 та 1347, які нам не потрібно показувати на головній. Щоб виключити ці категорії із запиту, використовуйте такий код у плагіні або темі:
add_action( 'pre_get_posts', 'exclude_category' ); function exclude_category( $query ) { if ( $query->is_front_page() && $query->is_main_query() ) { $query->set('cat', '-1,-1347'); } }
#3 Виключення постійних сторінок із результатів пошуку
Коли користувачі вашого сайту що-небудь шукають, часто в результатах пошуку можуть траплятися постійні сторінки, які в принципі зовсім не потрібні в результатах пошуку, і які можна виключити з пошуку назовсім. Використовуйте хук pre_get_posts, щоб виключити з результатів пошуку постійних сторінок:
add_action( 'pre_get_posts', 'search_filter'); function search_filter( $query ){ if( ! is_admin() && $query->is_main_query() && $query->is_search ){ $query->set('post_type', 'post'); } }
#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); } // Виводимо 50 записів, якщо це архів типу запису 'movie' if( $query->is_post_type_archive('movie') ){ $query->set( 'posts_per_page', 50); } }
#5 Приклад об’єкта WP_Query
Для того, щоб швидко розібратися як і що використовувати нижче приклад об’єкта WP_Query (global $wp_query ), який передається в хук за посиланням (&$query):
список змін
З версії 2.0.0 | Введено. |
Де викликається хук
Де використовується хук у WordPress
add_filter( 'pre_get_posts', '_resolve_template_for_new_post' );