Зачем нужен if(have_posts()), разве недостаточно while(have_posts())?

9 окт. 2013 г., 11:32:22
Просмотры: 51.2K
Голосов: 26

У меня вопрос о "цикле" (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 не обязательно.

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

Проголосовал до прочтения the_content, the_title оказался решающим!

brasofilo brasofilo
9 окт. 2013 г. 13:36:51

Отличная (финальная) правка. Большинство людей используют if и while непосредственно друг за другом, никогда не используя else. Вероятно, из-за копирования и вставки.

Herbert Van-Vliet Herbert Van-Vliet
5 мар. 2018 г. 04:59:10
Все ответы на вопрос 4
4
33

Загрузчик шаблонов WordPress включает соответствующий контекстный файл шаблона во многих случаях, даже если запрос для этого контекста не возвращает записей. Например:

  • Главный индекс записей блога
  • Архив категорий (категория существует, но не имеет записей)
  • Архив меток (метка существует, но не имеет записей)
  • Архив автора (автор существует, но не имеет записей)
  • Результаты поиска

Таким образом, в этих случаях будет загружен соответствующий файл шаблона, но записи не будут выведены, так как запрос не возвращает записей.

Примеры для демонстрации:

Поэтому в этих контекстах полезно включать условную проверку 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.

9 окт. 2013 г. 17:02:05
Комментарии

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

gmazzap gmazzap
9 окт. 2013 г. 20:00:59

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

Sunyatasattva Sunyatasattva
12 окт. 2013 г. 23:53:37

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

Sunyatasattva Sunyatasattva
12 окт. 2013 г. 23:55:00

"Безопасный" в данном контексте не имеет четкого определения.

Chip Bennett Chip Bennett
13 окт. 2013 г. 00:05:38
1
11

Ответ Chip действительно идеален, но если кратко:

Используйте часть с if, если хотите отображать что-то особенное, когда нет постов. Это особенно полезно, например, на страницах архивов по дате или категориям. Если кто-то перейдет на страницу без постов, лучше показать сообщение об этом, чем просто ничего не отображать (так как цикл вообще не выполняется).

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

И это все, что нужно знать.

Herbert Van-Vliet Herbert Van-Vliet
19 мая 2018 г. 00:08:22
0

Возможно, есть некоторые соображения, которые не были учтены в предыдущих ответах. Не рекомендуется пропускать оператор if.

Оператор if обычно используется для:

  • вывода сообщений, таких как записи не найдены, чтобы указать, что в рассматриваемой категории нет статей.
  • определения, нужно ли выводить окружающий HTML (например, ul) до и после статей.

Что если добавится новый хук?

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

Другие разработчики ожидают определённой структуры цикла WordPress

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

28 нояб. 2019 г. 13:24:39
2
-1

Я рассматриваю это как фундаментальный вопрос теории структуры управления. Закрытый блок внутри цикла 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; ?>
24 окт. 2014 г. 01:59:17
Комментарии

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

Tom J Nowell Tom J Nowell
24 окт. 2014 г. 02:27:59

Оператор if присутствует именно из-за else после него. Ни по какой другой причине. Если нет записей, то отображение понятного сообщения "нет записей" лучше, чем полное отсутствие вывода.

Otto Otto
24 окт. 2014 г. 03:13:09