我为什么要放if(have_posts()),而while(have_posts())还不够?


22

我对“循环”有疑问。

<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php endwhile; else: ?>
<p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
<?php endif; ?>

代码取自The Loop WordPress Codex页面

我为什么要if参加?好像有while循环,工作正常。

如果没有if声明,在什么情况下会出现问题?

编辑

我接受@Chip的回答。但老实说我只需要最后一部分。

我现在知道我想从我的问题中学到什么。

if仅当需要放置仅应写入一次的页眉或页脚时,才需要使用该语句。如果您不使用“包装器”,则if无需声明。


2
我在阅读the_content之前投票赞成,the_title是决定性的!
brasofilo

优秀(最终)编辑。大多数人彼此直接使用if和while,而从未使用过else。可能是因为复制粘贴。
Herbert Van-Vliet

Answers:


29

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,即使没有分配给该类别的帖子,查询也是有效的,并且会加载类别模板。

为什么?因为要解析的查询是(IIRC)&cat={ID}- 即使没有分配给该类别的帖子,这也是一个有效的查询,因此在解析时不会导致404。

在这种情况下,您将获得一个有效的查询,并加载了一个模板文件,但是没有posts。因此,if ( have_posts() ),其实相关的。同样,这是一个示例:存在类别,但未分配任何帖子。类别模板文件已加载,并if ( have_posts() )返回false

对于包含帖子变量(&p={ID})的查询(例如单个博客帖子和静态页面),这将不成立,因为该帖子实际上并不存在,并且在解析后,该查询将不会返回有效的对象。

编辑2

如果我正确理解类别模板中是否没有if(have_posts())并且类别没有帖子,那么即使它应该返回没有帖子的category-sample.php,它也会返回404.php。那正确吗?

否。请记住:已在选择模板template_redirect。因此,如果查询有效,那么将加载适当的模板文件。如果查询无效,则将加载404模板。

因此,一旦加载模板(例如类别模板),则在输出循环后,模板就不会更改

再看一下操作顺序:

  • parse_query
  • pre_get_posts
  • wp
  • template_redirect- 选择模板并在此处加载。这是无法回报的模板。此后,模板将无法更改。
  • ...
  • the_post- 在此设置postdata,作为循环调用的一部分。在模板内部被调用,并且模板不会根据查询对象中的可用数据而更改

最终编辑

我声称在检查帖子的存在时,为什么我应该运行两次相同的测试。从一开始我就是一直在问这个问题。

这样,我终于明白了:一直以来,您的问题与WordPressWordPress Loop无关。您在问有关whileif检查相同条件的条件中包装任意PHP 循环的问题。

这个问题不在WPSE的范围内,但我将简要说明:

一个if条件是一个二元的评价:它要么truefalse,会发生什么,里面是有条件的,执行一次

一个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条件包装器有很多用途,条件包装if器的用途while循环的用途完全不同


2
在我单一的帖子/页面模板中,很长一段时间以来,我the_post();之所以使用它只是因为也while不必要。+1为信息的完整性。
gmazzap

@GM可能删除该if( have_posts() )语句很有意义(这就是我要找出的含义),但不要仅仅使用the_post()在单数页面中!
Sunyatasattva

@ChipBennett所有人都考虑过,您认为if( have_post() )single-*.phppage-*.php模板文件的上下文中完整循环之前删除条件是否安全?
Sunyatasattva

1
在这种情况下,“安全”确实没有明确的含义。
Chip Bennett

10

确实不可能改善Chip的答案,而只是切入正题:

if如果您希望在没有帖子时显示其他内容,请使用该零件。例如,在日期或类别存档页面上,此功能特别有用。如果某人导航到没有帖子的页面,那么会有一条这样的消息而不是什么都没有出现是很高兴的,因为循环永远不会执行。

if ( have_posts() ):
  // Yep, we have posts, so let's loop through them.
  while ( have_posts() ) : the_post();
  // do your loop
  endwhile;
else :
  // No, we don't have any posts, so maybe we display a nice message
  echo "<p class='no-posts'>" . __( "Sorry, there are no posts at this time." ) . "</p>";
endif;

这就是所有需要知道的。
赫伯特·范弗利特

0

到目前为止,答案中可能还没有包括一些注意事项。不建议省略if语句。

if语句通常用于:

  • 输出类似于no posts found表明所涉及类别未分配任何文章的内容。
  • 决定是否在文章前后输出周围的html(如ul)。

如果添加了新的钩子怎么办?

不使用if语句的另一个可能的问题是,如果wordpress团队曾经决定添加一个新钩子,该钩子会在第一个钩子上触发 $wp_query->have_posts()调用时触发,那么它将在错误的时间触发。如果这导致了意外行为,则可能是由于您未正确遵循规范而造成的。

其他开发人员希望看到wordpress循环的特定结构

我想其他开发人员希望看到整个wordpress循环。因此,让他们搜索不存在的if语句可能不是一个好主意。


-1

我认为这是控制结构理论的基本问题。即使条件(have_posts())第一次被评估为false,while循环中包含的块也不会执行一次。

因此,if ( have_posts() )WordPress循环中的目的仅是在评估while条件之前执行一次have_posts()函数。如果have_posts()没有副作用,则if ( have_posts() )完全没有意义。如果have_posts()确实有副作用,则可以简化如下:

<?php have_posts(); ?>
<?php while ( have_posts() ) : the_post(); ?>
<?php endwhile; else: ?>
<p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
<?php endif; ?>

3
这种简化是无效的PHP,您有一个else语句,该语句没有附加的if语句。充其量是很难读的
汤姆·J·诺维尔

1
之所以if在那儿是因为else之后的事。没有其他原因。如果没有帖子,那么显示一个不错的“ no posts”消息比什么都不显示更好。
奥托(Otto)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.