Циклы WordPress

В этой статье:
Цикл WordPress и дополнительные циклы
функции have_posts(), the_post(), rewind_posts(), query_posts(), wp_reset_postdata()
объект WP_Query
глобальные массивы $wp_query $posts

Цикл WordPress

Цикл WordPress имеет такой вид:

// если есть записи
<?php if (have_posts()) : ?>
  // пока есть записи, извлекать по одной записи
  <?php while (have_posts()) : the_post(); ?>
    <!--обработка ... -->
  <?php endwhile; ?>
<?php endif; ?>

Функции have_posts() и the_post() работают с глобальным (global) объектом $wp_query, который вызывается в header блога. При этом формируется и выполняется запрос к базе данных (БД), возвращающий массив записей блога, который затем хранится в этом объекте, а также в глобальном массиве $posts (для обеспечения обратной совместимости).

have_posts() (вызывает $wp_query->have_posts()) проверяет, есть ли еще записи в массиве записей

the_post() (вызывает $wp_query->the_post()) заполняет глобальную переменную $post и все глобальные данные, связанные с текущей извлекаемой записью, и увеличивает счетчик цикла.

Несколько циклов на одной странице

Для того чтобы в случае необходимости выполнить цикл еще раз, нужно "отмотать все назад" с помощью функции

<?php rewind_posts(); ?>

Или можно использовать функцию query_posts(), которая выполняет новый запрос, создает новый массив записей и отматывает назад счетчик цикла.

Если нужно сохранить (не перезаписывать) результаты исходного запроса, можно создать копию $wp_query или создать новый объект запроса.

Использование функции query_posts()

// 10 последних записей из категории cat1
<?php query_posts('category_name=cat1&posts_per_page=10'); ?>
<?php while (have_posts()) : the_post(); ?>
...
<?php endwhile;?>

Внимание! Чтобы не нарушалась "пагинация" - работа ссылок "Предыдущие записи" - для функции query_posts() необходимо использовать параметр paged:

  $page_num = $paged;
  if ($pagenum='') $pagenum =1;
  query_posts('showposts=4&paged='.$page_num=3');

Рекомендации автора плагина PageNavi (wp_pagenavi ):

Плагин wp_pagenavi создает страничную навигацию (страница 1, страница 2 и т.д.) для страниц записей, но навигация не будет работать, если в теме используется вызов функции query_posts() вида

query_posts('cat=8');
или
query_posts( array( 'cat' => 8 ) );

Должно быть так:

query_posts( array( 'cat' => 8, 'paged' => get_query_var('paged') ) );

если это не сработает, попробуйте передать переменную page:

query_posts( array( 'cat' => 8, 'paged' => get_query_var('page') ) );

(http://scribu.net/wordpress/wp-pagenavi/right-way-to-use-query_posts.html)

Внимание! Использование функции query_posts() означает изменение глобального массива и не рекомендуется. Предпочтительнее создание нового объекта  WP_Query или применение фильтра pre_get_posts .

Создание нового объекта  WP_Query

Если нужно сохранить (не перезаписывать) результаты исходного запроса, можно создать копию $wp_query или создать новый объект запроса. Вот, например, два цикла: сначала вывод одной записи из рубрики featured и затем вывод последних добавленных записей, исключая первую выведенную запись

<?php $my_query = new WP_Query('category_name=featured&posts_per_page=1');
while ($my_query->have_posts()) : $my_query->the_post();
$do_not_duplicate = $post->ID; ?>
...
<?php endwhile; ?>
...
<?php if (have_posts()) : while (have_posts()) : the_post();
if( $post->ID == $do_not_duplicate ) continue;?>
...
<?php endwhile; endif; ?>

Или вывод нескольких записей в первом цикле:

<?php $my_query = new WP_Query('category_name=featured&posts_per_page=3');
while ($my_query->have_posts()) : $my_query->the_post();
 $do_not_duplicate[] = $post->ID ?>    // массив id записей
...
<?php endwhile; ?>
...
<?php if (have_posts()) : while (have_posts()) : the_post();
 if (in_array($post->ID, $do_not_duplicate)) continue;
 ?>
...
<?php endwhile; endif; ?>

Можно пойти и другим путем - сразу исключить из запроса записи из массива:

<?php query_posts(array('post__not_in'=>$do_not_duplicate));
 if (have_posts()) : while (have_posts()) : the_post();
 ?>

Вложенные циклы

Цикл внутри основного (по окончании внутреннего цикла продолжается внешний цикл ):

$my_query = new WP_Query( "cat=3" );
if ( $my_query->have_posts() ) {
  while ( $my_query->have_posts() ) {
   $my_query->the_post();
   the_content();
  }
}
// Установка некоторых глобальных переменных:
wp_reset_postdata();

Изменение количества записей только на главной странице - query_posts

Новый запрос с помощью функции query_posts():

<?php
if (is_front_page()) {
  $page_num = $paged;
  if ($pagenum='') $pagenum =1;
  query_posts('showposts=4&paged='.$page_num);
 }
 ?>

<?php //while ( have_posts() ) : the_post(); ?>

На главной будут выводиться 4 записи, а на страницах рубрик, меток и т.д.   - в соответствии с настройкой, заданной в

Параметры - Чтение - На страницах блога отображать не более 10 записей

Изменение запросов с помощью фильтра pre_get_posts

Фильтр pre_get_posts применяется после формирования запроса но до его выполнения, т.е. его использование не создает дополнительной нагрузки!

Исключение рубрик на главной странице

Если нужно не показывать  на главной / домашней странице записи блога из некоторых рубрик (например, с id= '1' и '67'), используйте в плагине или добавьте в файл functions.php код:

function exclude_category( $query ) {
    if ( $query->is_home() && $query->is_main_query() ) {
        $query->set( 'cat', '-1,-67' );
    }
}
add_action( 'pre_get_posts', 'exclude_category' );

Изменение количества записей для разных случаев

В WordPress есть одна глобальная настройка для количества записей на главной странице блога и на страницах рубрик, архивов по месяцам и т.д. (Параметры - Чтение). Применяя фильтр, можно избирательно изменять эту и другие настройки, например, для главной страницы или страницы определенной рубрики.

Пример изменения параметра 'posts_per_page' (записей на странице):

function change_posts_per_page( $query ) {
    // изменять не в админке и только главный запрос
    if ( is_admin() || ! $query->is_main_query() )
        return;

    if ( is_home() ) {
        // На главной показывать только 1 запись
        $query->set( 'posts_per_page', 1 );
        return;
    }

    if ( is_post_type_archive( 'movie' ) ) {
        // 50 записей в архиве произвольноготипа'movie'
        $query->set( 'posts_per_page', 50 );
        return;
    }
}
add_action( 'pre_get_posts', 'change_posts_per_page', 1 );

13 комментариев: Циклы WordPress

  1. Alexandr говорит:

    Спасибо за подробное объяснение.

  2. Арендатор говорит:

    А не знаете как изменить обрамление ссылки тега the_title(), который вызывает ссылку на запись (more), а то надо убрать которые обрамляет эту ссылку.

    • Admin говорит:

      Обрамление ссылки READ MORE (читать далее)?
      Стиль текста ссылки MORE (или READ MORE) задает класс стилей more-link
      Так что изменяй .more-link в файле темы style.css

      the_title() выводит заголовок статьи

  3. Александр говорит:

    Есть следующая задача: реализовать возможность изменения вида вывода для каждого пользователя. Используется два варианта вывода:
    1. Полный (изобрадение, описание, ссылка)
    2. Компактный (Миниатюра, ссылка)
    В шаблоне используется условие и два цикла.
    Первый выводит 5 полных записей(как указано в настройках)
    Как сделать чтобы один выводил не 5, а любое другое количество постов ??

  4. Admin говорит:

    ---выводит 5 полных записей(как указано в настройках)---
    5 задано в каких настройках?
    Параметры - Чтение -
    На страницах блога отображать не более 5 записей?

    • Александр говорит:

      Да. В настройках: Параметры - Чтение - На страницах блога отображать не более 5 записей.
      Для первого цикла это норма. Однако как сделать, чтобы второй выводил не 5, а скажем 30 ?

      • Admin говорит:

        Как показано в статье, перед выводом цикла можно выполнить новый запрос и в нем задать количество постов на странице:
        query_posts(...&posts_per_page=30&...)

        • Александр говорит:

          Да, это то, что мне нужно. Однако возникла ещё одна проблема: не работает сортировка по страницам и рубрикам. Вот мой код:

          dstyle) {print ''; query_posts('posts_per_page=32');
          while ( have_posts() ) : the_post(); get_template_part( 'content', 'all' ); endwhile;
          print ''; }
          else {
          while ( have_posts() ) : the_post(); get_template_part( 'content', get_post_format() ); endwhile; }
          getpagenavi(); ?>

          Результатом его работы ВСЕГДА являются 32 последние записи, независимо от выбранной рубрики или страницы пейджера...

          • Admin говорит:

            Посмотрите, в статью добавлены рекомендации по использованию функции query_posts: для query_posts нужно задавать параметр paged.
            Или вместо использования query_posts создайте новый объект запроса WP_Query.

          • Александр говорит:

            ПРОСТО АСТРАНОМИЧЕСКОЕ ВАМ СПАСИБО!!
            Всё получилось именно так, как мне нужно ))

  5. ashik говорит:

    умения на главный страниц отображается записа 2 записа,я из меню устанавливаю 10 записа но не изменяется,Пожалуйста подскажите какой файл php?? отвечает за это

  6. bubiz говорит:

    Спасибо за разъяснения по циклу query_posts(). Много перерыл по теме WP_Query(), но хотя советов много нашёл - в моём случае помогло только то, чем вы поделились со всеми для решения проблем в условиях вывода сортированных рубрик на главной странице и сохранения работоспособной пагинации при использовании плагина PageNavi (wp_pagenavi ).
    У меня получился вот такой рабочий код на одном из проектов:

    4,'paged' => get_query_var('paged'))); ?>
    ... вывод контента ...

    ... и всё заработало без попадания в предыдущие записи постов из других рубрик и ошибок при формировании пагинации.
    PS: Важно! Советую более КРУПНО прописать важность применения wp_reset_query() после использования цикла query_posts(), ибо многие не акцентируют внимание на "убийстве" этим циклом $wp_query и необходимости возврата основного запроса данной функцией, ведь это ведёт к подобным заморочкам, которые я решил при вашей помощи )))
    Удачи!

  7. bubiz говорит:

    Сорри, код не получился(((

    query_posts(array('cat'=>n,'paged' => get_query_var('paged')));
    if (have_posts()) : while (have_posts()) : the_post();

    ... вывод контента ...

    endwhile;
    wp_pagenavi();
    wp_reset_query();

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *