pre_get_posts как альтернатива query_posts

Популярных способов (функций) скорректировать стандартный цикл WordPress как минимум три:

  1. query_posts()codex.wordpress.org/Function_Reference/query_posts
  2. get_posts()codex.wordpress.org/Template_Tags/get_posts
  3. WP_Query()codex.wordpress.org/Class_Reference/WP_Query

Исчерпывающих руководств по ним на русском языке достаточно, повторять нет смысла, скажу лишь, что каждый из них имеет свои особенности и свойства, каждый решает свою задачу. Об одной из особенностей я не так давно писал — query_posts и постраничная навигация.

Недавно передо мной была поставлена задача — сформировать цикл для шаблона меток генерирующий список стандартных записей и записей произвольного типа ‘document’. Этот произвольный тип формировался с помощью плагина “WP Document Revisions” — wordpress.org/extend/plugins/wp-document-revisions. Я успешно сделал это с помощью query_posts() так:

// Коррекция условий
global $wp_query;
query_posts (
  array_merge(
    array(
      'post_type' => array( 'document', 'post' )
    ),
    $wp_query->query
  )
);

// Сам цикл
if (have_posts()){
 while ( have_posts() ) : the_post();
...
}

Список записей формировался корректно. Записи типа ‘document’, затем ‘post’. Проблема возникла с т.н. пагинацией — постраничной разбивкой. Количество страниц рассчитывалось корректно, но навигация возможна была лишь по одному из типу записей, по первому в списке. Т.е. перейдя на страницу содержащую записи второго типа получалась ошибка 404. При этом, мой же совет из записи — query_posts и постраничная навигация не работал.

Быстрый поиск не дал желаемого результата, с вопросом я обратился в G+ сообщество WordPress Russia, где и получил информацию об упущенном мной из внимания способе коррекции цикла:

… Вам нужно изменять цикл во время события pre_get_posts или через фильтр request. Тогда и с пагинацией будет всё в порядке, и по два запроса на страницу делать не придётся. — Konstantin Kovshenin.

Решил, что воспользуюсь хуком pre_get_posts через add_filter, так как я счел его проще в сравнении с фильтром request в котором используется знакомый WP_Query().

Несколько откорректировал пример из Codex, и получил полностью удовлетворивший меня результат с работающей пагинацией:

function addDocument($var) {
  if ( $var->is_tag() && $var->is_main_query() ) {
    $variable->set( 'post_type', (array( 'document', 'post' )) );
  }
  return $var;
}
add_filter('pre_get_posts', 'addDocument');

В данном случае изменения цикла коснутся только страницы меток, но изменив условный тэг (Conditional tag) is_tag() на другой можно добиться аналогичного результата для других шаблонов.

Надеюсь, что мой опыт окажется полезным и вам.

Источники:
codex.wordpress.org/Plugin_API/Action_Reference/pre_get_posts
codex.wordpress.org/Plugin_API/Filter_Reference/request
codex.wordpress.org/Conditional_Tags

Опубликовано

Обратите внимание на предыдущие записи: