Зачем нужен if(have_posts()), разве недостаточно while(have_posts())?
У меня вопрос о "цикле" (the loop).
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php endwhile; else: ?>
<p><?php _e('Извините, записей соответствующих вашим критериям не найдено.'); ?></p>
<?php endif; ?>
Код взят со страницы WordPress Codex о Цикле.
Зачем нужно использовать часть с if
?
Кажется, что если есть цикл while
, всё работает нормально.
В каких случаях могут возникнуть проблемы, если не использовать условие if
?
Редактирование
Я принял ответ @Chip, но честно говоря, мне нужна была только последняя часть.
Теперь я знаю то, что хотел узнать из своего вопроса.
Условие
if
нужно только тогда, когда необходимо вывести заголовок или подвал, которые должны быть написаны только один раз. Если вы не используете "обертку", тогда условиеif
не обязательно.

Загрузчик шаблонов WordPress включает соответствующий контекстный файл шаблона во многих случаях, даже если запрос для этого контекста не возвращает записей. Например:
- Главный индекс записей блога
- Архив категорий (категория существует, но не имеет записей)
- Архив меток (метка существует, но не имеет записей)
- Архив автора (автор существует, но не имеет записей)
- Результаты поиска
Таким образом, в этих случаях будет загружен соответствующий файл шаблона, но записи не будут выведены, так как запрос не возвращает записей.
Примеры для демонстрации:
- Категория существует, но не имеет записей (загружается шаблон категории)
- Категория не существует (загружается шаблон 404)
Поэтому в этих контекстах полезно включать условную проверку if ( have_posts() )
в файле шаблона.
В других контекстах файл шаблона никогда не будет загружен, если запрос не возвращает записей. Например:
- Отдельная запись блога
- Статическая страница
В этих контекстах использование if ( have_posts() )
, вероятно, излишне.
Редактирование
Я понимаю, что запрос вызывается с помощью the_post(), верно? И если while(have_posts()) существует, запрос никогда не происходит, если нет записей.
Чтобы понять, что происходит, нужно посмотреть порядок действий WordPress. Начиная с wp_loaded
(и опуская некоторые для ясности):
wp_loaded
parse_request
send_headers
parse_query
pre_get_posts
wp
template_redirect
get_header
wp_head
the_post
wp_footer
Итак, что происходит и в каком порядке?
- Выполняется запрос:
parse_query
pre_get_posts
wp
- Выбирается шаблон:
template_redirect
- Шаблон загружается/выводится. Следующие действия запускаются шаблоном:
get_header
wp_head
the_post
dynamic_sidebar
get_footer
wp_footer
Таким образом, the_post
, запускаемый с помощью the_post()
, происходит гораздо позже, чем выполняется запрос, получаются записи и загружается шаблон.
Я очень благодарен, что вы предоставили много информации, о которой я не знал, но это не то, о чем я спрашивал.
О, но я считаю, что это именно то, о чем вы спрашивали.
Реальный вопрос: что является допустимым возвратом запроса? Для таких контекстов, как архив категорий, запрос является допустимым, и шаблон категории загружается, если запрашиваемый ID категории существует, даже если нет записей, связанных с этой категорией.
Почему? Потому что разбираемый запрос (если я правильно помню) — это &cat={ID}
, который является допустимым запросом даже если нет записей в этой категории, и поэтому не приводит к 404 при разборе.
В этом случае вы получаете допустимый запрос и загруженный файл шаблона, но без записей. Таким образом, if ( have_posts() )
действительно актуален. Вот пример: категория существует, но не имеет записей. Загружается шаблон категории, и if ( have_posts() )
возвращает false
.
Это не будет верно для запросов, которые включают переменную post (&p={ID}
), таких как отдельные записи блога и статические страницы, потому что запись не будет существовать, и при разборе запрос не вернет допустимый объект.
Редактирование 2
Если я правильно понимаю, если в шаблоне категории нет if(have_posts()) и в категории нет записей, то возвращается 404.php, хотя должен возвращаться category-sample.php без записей. Это так?
Нет. Помните: шаблон выбирается на этапе template_redirect
. Поэтому, если запрос допустим, загружается соответствующий файл шаблона. Если запрос недопустим, загружается шаблон 404.
Таким образом, как только шаблон загружен — например, шаблон категории — после вывода цикла шаблон не меняется.
Посмотрите еще раз порядок действий:
parse_query
pre_get_posts
wp
template_redirect
— здесь выбирается и загружается шаблон. Это точка невозврата шаблона. Шаблон не может измениться после этого момента.- ...
the_post
— здесь устанавливаются данные записи как часть вызова цикла. Это вызывается внутри шаблона, и шаблон не меняется в зависимости от доступных данных в объекте запроса.
Финальное редактирование
И я утверждаю, что while проверяет наличие записей, зачем мне делать ту же проверку дважды. Это мой вопрос с самого начала, я спрашивал только об этом.
И теперь я наконец понимаю: все это время ваш вопрос не имел отношения к WordPress или Циклу WordPress. Вы спрашиваете о том, чтобы обернуть любой произвольный PHP while
цикл в условное выражение if
, которое проверяет то же условие.
Этот вопрос выходит за рамки WPSE, но я кратко объясню:
Условное выражение if
— это бинарная оценка: оно либо true
, либо false
, и то, что происходит внутри этого условия, выполняется один раз.
Условное выражение while
— это цикл: оно остается истинным в течение некоторого дискретного периода, основанного на каком-то счетчике; и то, что происходит внутри этого условия, выполняется несколько раз — один раз для каждой итерации счетчика.
Допустим, вы хотите вывести неупорядоченный список элементов, если список элементов заполнен. Если вы используете цикл while
и опускаете обертку if
, ваша разметка будет выглядеть так:
<ul>
<?php while ( list_of_things() ) : ?>
<li><?php the_list_item(); ?></li>
<?php endwhile; ?>
</ul>
И если list_of_things()
пуст, вывод будет таким:
<ul>
</ul>
Что оставляет ненужную (и недопустимую) разметку.
Но если вы добавите обертку if
, вы можете сделать так:
<?php if ( list_of_things() ) : ?>
<ul>
<?php while ( list_of_things() ) : ?>
<li><?php the_list_item(); ?></li>
<?php endwhile; ?>
</ul>
<?php endif; ?>
И если list_of_things()
пуст, разметка вообще не будет выведена.
Это всего лишь один пример. Есть множество применений для этой обертки if
, и она служит совершенно другой цели, чем цикл while
.

В моих шаблонах для отдельных записей/страниц я уже давно использую только the_post();
, так как цикл while
также не нужен. +1 за полноту информации.

@G.M. Возможно, удаление условия if( have_posts() )
имеет смысл (это я и пытаюсь выяснить), но не используйте просто the_post()
на отдельных страницах!

@ChipBennett Учитывая всё вышесказанное, считаете ли вы безопасным удаление условия if( have_post() )
перед полным циклом в контексте файлов шаблонов single-*.php
и page-*.php
?

Ответ Chip действительно идеален, но если кратко:
Используйте часть с if
, если хотите отображать что-то особенное, когда нет постов. Это особенно полезно, например, на страницах архивов по дате или категориям. Если кто-то перейдет на страницу без постов, лучше показать сообщение об этом, чем просто ничего не отображать (так как цикл вообще не выполняется).
if ( have_posts() ):
// Да, у нас есть посты, давайте пройдемся по ним.
while ( have_posts() ) : the_post();
// ваш цикл
endwhile;
else :
// Нет, постов нет, можно вывести вежливое сообщение
echo "<p class='no-posts'>" . __( "Извините, в данный момент нет записей." ) . "</p>";
endif;

Возможно, есть некоторые соображения, которые не были учтены в предыдущих ответах. Не рекомендуется пропускать оператор if.
Оператор if обычно используется для:
- вывода сообщений, таких как
записи не найдены
, чтобы указать, что в рассматриваемой категории нет статей. - определения, нужно ли выводить окружающий HTML (например,
ul
) до и после статей.
Что если добавится новый хук?
Ещё одна потенциальная проблема при отказе от использования оператора if заключается в том, что если команда WordPress решит добавить новый хук, срабатывающий при первом вызове $wp_query->have_posts()
, он активируется в неподходящий момент. И если это вызовет неожиданное поведение, вина ляжет на вас за несоблюдение спецификации.
Другие разработчики ожидают определённой структуры цикла WordPress
Предполагается, что другие разработчики ожидают увидеть полный цикл WordPress. Поэтому, возможно, плохая идея заставлять их искать отсутствующий оператор if.

Я рассматриваю это как фундаментальный вопрос теории структуры управления. Закрытый блок внутри цикла while не выполнится ни разу, если условие (have_posts()) при первой проверке окажется ложным.
Таким образом, цель использования if ( have_posts() )
в цикле WordPress заключается только в том, чтобы выполнить функцию have_posts() один раз до проверки условия while. Если have_posts()
не имеет побочных эффектов, то if ( have_posts() )
абсолютно бессмыслен. Если же have_posts()
имеет побочные эффекты, можно упростить код следующим образом:
<?php have_posts(); ?>
<?php while ( have_posts() ) : the_post(); ?>
<?php endwhile; else: ?>
<p><?php _e('Извините, нет записей, соответствующих вашему критерию.'); ?></p>
<?php endif; ?>

Такое упрощение является некорректным PHP-кодом - у вас есть оператор else, не привязанный ни к какому if. В лучшем случае это затрудняет чтение кода
