have_posts() – проверяет наличие постов для вывода на странице

Циклы – не самая лёгкая для понимания тема в изучении WordPress, поэтому возможно вам будет легче изучить её при помощи моего видеоурока.

Обратите внимание, что эта функция только для основного цикла. Если мы работаем с дополнительным циклом при помощи WP_Query, то используем метод класса WP_Query::have_posts().

Ещё раз о том, что делает функция, подробнее:

  • Когда вы используете её в качестве условия на странице if( have_posts() ) – тут всё просто, если есть посты на странице – return true, нет – false.
  • Когда используется в цикле while( have_posts() ), ситуация становится интереснее. Как вы знаете, у нас есть функции для вывода параметров текущего поста, например the_title(), the_permalink(). Как они определяют, что это тот самый пост? При помощи функции the_post(), которая при каждой итерации цикла хватает следующий пост в очереди. А что происходит, когда очередь заканчивается? – тогда while ( have_posts() ) возвращает false и цикл завершается. Однако (!) в то же время функция have_posts() также делает и сброс значения текущего поста, возвращаясь к самому первому на этой странице! 🎉

Пример 1. Стандартно

В шаблонах тем WordPress можно часто встретить подобную запись:

if( have_posts() ) :
 
	while( have_posts() ) : the_post();
 
		// тут обычно что-то происходит        
 
	endwhile;
 
else :
	echo 'Ничего не найдено на этой странице';
endif;
  • Сначала при помощи условия if ( have_posts() ) :, мы проверяем, есть ли вообще посты на этой странице? Это может быть страница рубрики, или главная – неважно. Если эта, предположим рубрика, пуста, то выводим «Ничего не найдено…» и больше ничего не делаем.
  • На строчках 3-7 мы проходим циклом по всем постам на странице «до тех пор, пока есть посты» и что-то делаем в теле цикла, например выводим заголовок поста через the_title() или же подключаем HTML/PHP темплейт записи функцией get_template_part() (это довольно часто встречается в темах).
  • Если убрать на 3-й строке функцию the_post(), то мы получим бесконечный цикл, потому что что the_post() сдвигает значение ткущего поста к следующему и в один момент, когда ей уже будет некуда сдвигать, have_posts() вернёт false, а если не производить «этот сдвиг», то have_posts() всегда будет возвращать true.

Пример 2. Множество циклов

Такую запись можно встретить не часто, однако она важна для понимания сути.

while( have_posts() ) : the_post();
 
	// тут обычно что-то происходит        
 
endwhile;
 
while( have_posts() ) : the_post();
 
	// невероятные вещи продолжают происходить     
 
endwhile;

Как такая запись вообще возможна?

Об этом я и говорил в самом начале, когда упомянул сброс цикла. Когда функция the_post() доводит цикл до конца, у нас происходит сразу две вещи:

  1. have_posts() возвращает false,
  2. have_posts() сбрасывает цикл, устанавливая значение текущего поста на самый первый пост на странице;

Пример 3. Хитрое условие для последнего поста цикла

Или ещё можно сказать – для последней итерации цикла while ( have_posts() ). Обычно, когда идёт разговор об итерациях цикла, первое, что приходит в голову (мою), это уроки информатики с переменными-счетчиками.

Но только не сегодня.

while( have_posts() ) : the_post();
 
	// ... выводится пост например
 
	if( ! have_posts() ) { 
		echo 'это последний пост цикла';
	}
endwhile;

Стоп! Не копируйте, прошу!

Что думаете про этот код? Норм или что-то смущает?

Представьте:

  1. Идёт последняя итерация цикла, выводится последний пост.
  2. Затем функция have_posts() (строка 5) определяет, что это последний пост, возвращает false, и соответственно выводится месседж «это последний пост цикла».
  3. И вроде бы всё хорошо и цикл должен закончиться, однако have_posts() сбрасывает текущий пост цикла и всё начинается снова, так и не закончившись!

Как исправить? Вместо условия have_posts() на 5-й строке используем другое условие:

	global $wp_query;
	if( $wp_query->current_post + 1 == $wp_query->post_count ) {
		echo 'это последний пост цикла';
	}

Миша

В последние годы я долго не знал, что мне делать с сайтом misha.blog, ведь он практически не приносит никакого профита, но недавно я осознал, что моя миссия – способствовать распространению WordPress. Ведь WordPress – это лучший движок для разработки сайтов – как для тех, кто готов использовать заложенную структуру этой CMS, так и для тех, кто предпочитает headless решения.

Сам же я впервые познакомился с WordPress в 2009 году. Организатор WordCamp. Преподаватель в школах Epic Skills и LoftSchool.

Если вам нужна помощь с вашим сайтом или может даже разработка с нуля на WordPress / WooCommerce — пишите. Я и моя команда сделаем вам всё на лучшем уровне.

Комментарии — 2

  • Александр 14 июня 2020 #

    Привет, Миш! Еще раз спасибо за твою работу и твой вклад в наши головы)
    Тут есть такой вопрос по выводу постов. На главной странице есть вывод постов определенной категории:

    $query = new WP_Query( array(
                            'category_name'  =>  'uncategorized',
                            'posts_per_page' =>  10,
                        ) );
     
    if( $query->have_posts() ) { 
      while( $query->have_posts() ) { 
         get_template_part( '/template-parts/tipa-post' );
      }
    } 
    wp_reset_postdata();

    Если мы подключаем стартовый контент для темы напр

    $starter_content = array(
       'posts' => array(
          'post1' => array(
    					'post_type' => 'post',
    					'post_title' => 'Lorem ipsum',
    					'post_excerpt' => __( 'Short description', 'theme' ),
    					'post_content' => __( 'This is the content of the post.', 'theme' ),
    					'thumbnail' => '{{start1}}',
    				),
        );
        ... тут еще виджеты всякие, навигация и тд...
    );
    add_theme_support( 'starter-content', $starter_content );

    то вывода постов в превью кастомайзера не видно, т.е. виджеты есть, навигация, текст, настройки все есть, но постов нет. Я подумал что это связано с тем, что мы запрашиваем посты через WP_Query, а постов самих в базе еще нет и соответсвенно вывода тоже. Но страницы же есть. После клика по кнопке "опубликовать" в кастомайзере, посты эти добавляются.

    Возможно ли сделать так чтобы этот вывод постов работал сразу в превью кастомайзера ?

    • Миша 15 июня 2020 #

      Привет! Да, всегда пожалуйста 🙃

      🤷‍♂️

Оставить комментарий

Если вы хотите добавить код, не забудьте обернуть его в <pre lang="php"></pre>, если же код – меньше одной строчки, то можно и в <code></code>.