WordPress как на ладони
wordpress jino

Что такое цикл «the loop» в WordPress

Начал отвечать на один из комментариев о цикле loop в WordPress и решил, что это тема выходит за рамки ответа на комментарий. Этот пост может стать полезен новичкам и тем, кто еще плохо понимает как работает Цикл вывода записей в WordPress.

Что такое цикл в WordPress?

Начну с того, что говорить «цикл loop» — это неправильно. Это тоже самое, что сказать, - «цикл цикл», т.е. loop = цикл = повторяющееся действие. Правильно говорить просто «Цикл WordPress». Далее в тексте «Цикл WordPress» — тоже самое, что «loop», «the loop» или «цикл the loop WordPress».

Итак, цикл в WordPress выглядит так:

<?php if ( have_posts() ) :  while ( have_posts() ) : the_post(); ?>
   <!-- 
	здесь формирование вывода постов,
	где работают теги шаблона относящиеся к the loop, например, the_title()
	-->
<?php endwhile; ?>
<?php endif; ?>

Однако у цикла WordPress могут быть и другие обличья, например он может выглядеть еще и так:

<?php
global $post;
$myposts = get_posts('numberposts=5&offset=1&category=1');
foreach( $myposts as $post ){
	setup_postdata( $post );
	?>
	<!-- 
	здесь формирование вывода постов,
	где работают теги шаблона относящиеся к the loop, например, the_title()
	-->
	<?php 
}
wp_reset_postdata();
?>

Если давать общее определение циклу в WordPress, то я бы сказал так: the loop - это цикл который перебирает массив содержащий в себе информацию о постах и во время перебора выводит информацию о каждом посте. При этом в цикле используются специально созданные для него теги шаблона: the_title(), the_permalink(), the_date() и т.д.

Вся информация о посте хранится в переменной $post. Предположим, что цикл обрабатывает массив содержащий в себе данные 10 постов, тогда у цикла будет 10 повторений и переменная $post будет меняться 10 раз, и при каждом повторении с переменной $post будет считываться информация о посте и выводится на экран, через теги шаблона: the_title(), the_content(). Также любой PHP или HTML код помещенный в цикл WordPress будет повторятся пока работает цикл: 10 итераций цикла - 10 повторений.

Типичный пример такого цикла — это вывод постов на странице категорий, меток, на главной странице WordPress.

Для чего нужно различать цикл WordPress?

Понимать где используется цикл нужно, потому что в WordPress есть определенные теги шаблона, которые не работают за пределами цикла, например: the_title(), the_content(), the_excerpt() и т.д. Для того, чтобы каждая такая функция (тег шаблона) сработала, должна быть определена переменная $post, которая за пределами цикла WordPress неизвестна (точнее не корректна, если цикл запускался, то $post известна - она содержит данные последнего, обработанного в цикле поста, но это уже другая тема).

Полный пример цикла

Приведу пример цикла WordPress (взял из Кодекса), со встроенными в код комментариями (внутри <!-- -->)

<!-- Проверка наличия записей в цикле -->
<?php if ( have_posts() ) : ?>

	<!-- Начало цикла -->
	<?php while ( have_posts() ) : the_post(); ?>
		<!-- Здесь уже определилась переменная $post, -->
		<!-- на основе которой будет строится дальнейший код. -->
		<!-- $post будет меняться для каждого поста while( have_posts() ). -->
		<!-- $post нужна, чтобы работали теги шаблона: in_category('3'), the_permalink() и т.д. -->

		<!-- Проверка находится ли этот пост в категории 3. -->
		<!-- Если да, то задаем CSS класс div-у class="post-cat-three". -->
		<!-- Если нет, то класс будет post class="post". -->
		<?php if ( in_category('3') ) { ?>
				  <div class="post-cat-three">
		<?php } else { ?>
				  <div class="post">
		<?php } ?>

		<!-- Выводим заголовок поста, как ссылку на сам пост. -->
		<h2><a href="<?php the_permalink() ?>" title="Ссылка на: <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>

		<!-- Выводим дату поста и ссылку на другие записи автора. -->
		<small><?php the_time('F jS, Y') ?> Автор: <?php the_author_posts_link() ?></small>

		<!-- Выводим текст поста в теге div. -->
		<div class="entry">
		   <?php the_content(); ?>
		</div>

		<!-- Выводим категории поста, через запятую. -->
		<p class="postmetadata">Расположено в <?php the_category(', '); ?></p>
		</div> <!-- закрываем основной тег div -->

		<!-- Отсюда цикл начинает повторятся, если есть еще посты -->
		<!-- Останавливаем цикл (endwhile), -->
	<?php endwhile; ?> 
	<!-- Полное окончание цикла. -->

<!-- Если записей в цикле нет, т.е. если цикл не сработал (else), выводим сообщение. -->
<?php else: ?>

	<p>Нет постов в цикле.</p>

<?php endif; ?>
Что такое цикл «the loop» в WordPress 35 комментариев
Вопросы 2 Все
  • Ihor

    100% полезный блог-инфо... В закладки, в избранное, и пиар, пиар, пиар. Автору великий РЕСПЕКТ bravo

    Ответить2.3 года назад #
    3
  • Здравствуйте!
    Объясните, пожалуйста, почему цикл WP рассматривается неразрывно с конструкцией if (have_posts())?
    В док-тации написано (http://codex.wordpress.org/Цикл_в_действии, п. "Начало цикла"):

    Так, до тех пор, как функция have_posts () возвращает истинное значение, цикл whileбудет продолжать цикл (повторения). Если есть следующий элемент, оператор if вновь возвращает ответ 'true' (верно) и оператор while используется вновь.

    Вот выделенное мне непонятно. Я полагал, что в if (have_posts()) просто проверяется наличие постов (один раз перед циклом) и, если возвращается true, запускается цикл - исключительно в while, в кот-ом последовательно (опять же, за счёт have_posts()) проводятся операции над всеми постами.
    Поэтому и не пойму: почему в документации указано, что if используется каждый раз, когда нужно запустить цикл?
    Вы вот тоже написали в примере комментарий

    Полное окончание цикла.
    лишь в части else, хотя цикл вроде бы закончил свою работу в if...

    Ответить2 года назад #
    1
    • Kama4081

      Вы все правильно говорите и это ошибка с моей стороны и в документации не совсем правильно видимо. Сейчас поправлю свою статью спасибо за замечание!

      if( have_posts() ) действительно всего один раз проверяет есть ли вообще записи для обработки в цикле. В частности для страниц типа is_single() чаще всего эту проверку можно вообще убрать.

      В защиту скажу. Я написал так и в доках написано так, потому что в php принято проверять все прежде чем что-то делать, поэтому немного не логично, но правильно всегда предполагать использование if( have_posts() ) вместе с while.

      Ответить2 года назад #
      2
      • Спасибо!
        Ещё непонятный момент:

        <?php
        global $post; //*1*
        $myposts = get_posts('numberposts=5&offset=1&category=1');
        foreach( $myposts as $post ){
        	setup_postdata( $post );
        ?>
        	<!--здесь формирование вывода постов-->
        <?php } ?>

        Для чего строка 1, если в цикле не используется $post из строки 1, а создаётся другая переменная $post (в качестве её значения - элемент массива $myposts (записываемый не по ссылке, а по значению, т.к. нет оператора &), который обновляется при каждой итерации)? Или глобальная $post нужна для работы get_posts()? Просмотрел код get_posts(), вроде не увидел её использования...
        Проясните, пожалуйста.

        Ответить2 года назад #
        • Kama4081

          Глобальная $post нужно для корректной работы setup_postdata() в коде есть такая строка:

          do_action_ref_array( 'the_post', array( &$post, &$this ) );

          изменяет переданную переменную по ссылке и нужно чтобы она была глобальной... В этом случае переменная $post становится глобальной, это нужно если такой цикл будет использоваться внутри функции. Можно еще так записать:

          $myposts = get_posts('numberposts=5&offset=1&category=1');
          foreach( $myposts as $post ){
          	global $post; //*1*
          	setup_postdata( $post );
          	// вывод
          }

          Но это насколько я понимаю это одно и тоже, но на 100% я не уверен, можно проверить...

          Ответить2 года назад #
          • В том-то и дело, что setup_postdata() берёт данные из $myposts, а не основываясь на переменной $post (сужу как php-программист, в WP, повторюсь, новичок). Но, мне кажется, я Вас понял: действительно, цикл не использует начальное значение $post - он его перезаписывает, как в банальном коде ниже:

            $p = 5; //аналог глоб. $post
            $arr = array(1,2,3,1060); //аналог рез-та get_posts()
            foreach ($arr as $p) { //*2*
            	var_dump($p); //1,2,3,1060 - 5 и близко нет, т.к. $p == 5
            //не присутствует в массиве
            }
            echo '<br>';
            var_dump($p); //НО из-за того, что в строке *2* элемент массива присвоили
            //в существующую вне цикла переменную $p, она перезаписалась

            Видимо, аналогично:

            <?php
            global $post; //*1*
            $myposts = get_posts('numberposts=5&offset=1&category=1');
            foreach( $myposts as $post ){ //здесь ГЛОБАЛЬНАЯ за счёт строки *1*
            //$post будет перезаписана значением элемента массива
            //и передана в setup_postdata(). Знач-е действительно
            //будет передано по ссылке - за счёт одинаковости имён.
            //Значение $post будет меняться от итерации к итерации.
            //Изящно, однако! :)
            	setup_postdata( $post );
            ?>
            	<!--формирование вывода постов-->
            <?php } ?>

            Кстати, если я прав, то в строке "global $post; // не обязательно" всё-таки обязательно (если речь о ф-циях). Иначе setup_postdata() не получит $post по ссылке.

            Ответить2 года назад #
            • Kama4081

              Да, в данном случае global $post; обязательно, если такой цикл используется внутри функции.

              Ответить2 года назад #
  • Здравствуйте ещё раз, Тимур!)
    В данной статье:

    $myposts = get_posts('numberposts=5&offset=1&category=1'); //всё работает

    В этой статье:

    Важное отличие get_posts() — функция принимает параметры в виде массива и не понимает параметры в виде строки ('cat=-3&nopaging=1')

    Ответить2 года назад #
    • Kama4081

      Спасибо за коммент, это ерунда - в виде строки принимает. Сейчас удалю эту заметку, что-то я погнал, когда писал.

      Ответить2 года назад #
      1
  • Игорь

    Здравствуйте, Kama.

    Во-первых, спасибо за ваш сайт. Кучища полезной и незаменимой информации, не зря ваш сайт висит в топе по все запросам-тегам ВП.

    Во-вторых, имею пару вопросовsmile

    1. Как организовать в пределах одного цикла следующую конструкцию:
      http://savepic.su/4839990.jpg
      с тумбой выводится последняя статья из рубрики, справа выводятся ссылки на последующие статьи тайтлами.

    2. Если на главной странице сайта я вывожу несколько блоков материалов разных категорий. Правильной ли будет следующие куски кода, располагающиеся на одной странице.
    $news_query = new WP_Query('category_name=novosti&showposts=3');
    if (have_posts()) : while ($news_query->have_posts()) : $news_query->the_post();
    ...
    
    $sport_query = new WP_Query('category_name=sport&showposts=3');
    if (have_posts()) : while ($sport_query->have_posts()) : $sport_query->the_post();
    ...

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

    Спасибо.

    Ответить2 года назад #
    • Kama4081
      // первый вывод из Новости
      $my_query = new WP_Query('category_name=novosti&showposts=3');
      $i = 0;
      if( $my_query->have_posts() ){
      	while( $my_query->have_posts() ){ $my_query->the_post();
      		if( ++$i==1 ){
      			// вывод первого блока с миниатюрой
      		}
      		else {
      			// вывод остальных записей
      		}
      	}
      }
      
      // второй вывод из Спорт
      // используем одну и туже переменную, чтобы не раздувать память без нужды
      $my_query = new WP_Query('category_name=sport&showposts=3');
      if( $my_query->have_posts() ){
      	while( $my_query->have_posts() ){ $my_query->the_post();
      		// вывод остальных записей
      	}
      }
      Ответить2 года назад #
      1
  • Здравствуйте. Появилась необходимость не учитывать текущую итерацию или как-то иначе.
    Суть такова что нужно вывести посты со стримами. Они могут не транслироваться и поэтому не активные не нужно выводить. Проверить активны они или нет можно только внутри цикла. Можете что-то подсказать?

    Ответить1.4 года назад #
    • Kama4081

      Не понятно... куда пишется активен пост или нет, в произвольные поля? Исключить записи из цикла можно:

      1. либо в самом цикле проверкой, например для метаполя:
      if( get_post_meta( $post->ID, 'название_поля', 1) ) continue;
      1. либо исключить из запроса, для этого смотрите хук pre_get_posts.
      Ответить1.4 года назад #
      1
      • Спасибо. Continue в моем случае не подойдет (пагинация будет начинаться не с 10 поста, а раньше).
        Но может я туплю, но как вытащить значения поста с pre_get_posts? Как изменять цикл понятно. Можете привести пример как допустим выдернуть id поста.
        Есть идея простосделать 2 цикла, в одном получать id постов, а во втором подставлять и выводить уже действующие. Как считаете это разумное решение?

        Ответить1.4 года назад #
        • Kama4081

          Я не понял что нужно и чем дальше тем не понятнее. Примеры что и как можно делать есть в описании pre_get_posts.

          Ответить1.4 года назад #
  • Сергей

    День добрый! Прошу помощи в такой задаче smile Необходимо что бы записи выводились блоками, ну дизайн такойwink 3 записи окруженные DIVом, затем еще 3 записи и до тех пор пока записи не закончаться )))
    Я понимаю что это цикл в цикле, но если так, то каждый цикл начинается с начала, то есть 1,2,3 запись и снова 1,2,3... а надо что бы 1,2,3 затем 4,5,6...
    Есть варианты как решить этот вопрос? Заранее благодарю!

  • рафаэль

    автору великий респект 1000 класс просто спасибо огромное

  • dotcom cайт: 21

    Добрый день автор ответьте пожалуйста ,Этот код , выводит только четыре моих записи из рубрики а всего записей семь , если пишу showposts, выводит все записи из всех рубрик , у меня есть вкладка рубрика 1 , я захожу в нее , и у меня должны выводится все записи этой рубрики а выводится только 4 , первая строка только. ПОМОГИТЕ Пожалуйста !!

    Ответить4 месяца назад #

Здравствуйте, !

Ваш комментарий