问题描述
我有一个关于”the loop” 的问题。
<?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 page 。
为什么要把 if
放在一起?好像是有 while
循环,工作正常。
在没有 if
语句的情况下会发生什么情况?
Edit
我接受了 @ Chip 的回答。但老实说,我只需要最后一部分。
我现在知道我想知道的问题。
if
statement is only when necessary, if you want to put a header or footer that should be write only once. if you don’t use the “wrapper”, thenif
statement is not necessary.
最佳解决方案
WordPress 模板加载程序将在许多情况下包含适当的上下文模板文件,即使该上下文的查询不返回任何帖子。例如:
-
主要博客文章索引
-
类别归档索引 (类别存在,但没有帖子)
-
标签存档索引 (标签存在,但没有帖子)
-
作者存档索引 (作者存在,但没有帖子)
-
搜索结果索引
因此,在这些情况下,将加载适当的模板文件,但不会输出任何帖子,因为查询不返回帖子。
Proof-of-concept 示例:
-
Category does not exist(包括 404 模板)
因此,在这些上下文中,模板文件包含 if ( have_posts() )
条件有用。
在其他上下文中,如果查询不返回任何帖子,模板文件将永远不会被加载。例如:
-
单个博文
-
静态页面
在这些情况下,if ( have_posts() )
可能是不必要的。
Edit
I understand the query is invoked by the_post(), right? And if while(have_posts()) exist, the query is never occurs if there is no post.
要了解发生了什么,you have to look at the order of WordPress actions 。从 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
会在查询被解析后发生很长时间,并且将模板加载。
I’m very grateful that you give a lot of information that I didn’t know, but this is not what I asked.
哦,但我相信这正是你所问的。
真正的问题是:什么是有效的查询返回?对于诸如类别归档索引的上下文,查询是有效的,并且如果查询的类别 ID 存在,则加载类别模板,即使没有分配给该类别的帖子。
为什么?因为正在解析的查询是 (IIRC)&cat={ID}
– 即使没有分配给该类别的帖子也是一个有效的查询,因此在解析时不会导致 404 。
在这种情况下,您会收到一个有效的查询,并加载了一个模板文件,但没有发布任何帖子。因此,if ( have_posts() )
,其实是相关的。再次,这里有一个例子:category 存在,但没有分配任何帖子。加载类别模板文件,if ( have_posts() )
返回 false
。
对于包含一个 post 变量 (&p={ID}
) 的查询 (例如单个博客文章和静态页面),这并不适用,因为该帖子实际上不存在,并且在解析时,该查询将不会返回一个有效的对象。
编辑 2
If I rightly understand if there is no if(have_posts()) in a category template and the category have no post, then it return 404.php, even though it should be return category-sample.php without post. Is that right?
不记得:模板是在 template_redirect
中选择的。所以如果查询是否有效,那么加载相应的模板文件。如果查询无效,则加载 404 模板。
所以,一旦模板被加载 – 例如类别模板 – 一旦循环输出,模板不会更改。
再看一下行动的顺序:
-
parse_query
-
pre_get_posts
-
wp
-
template_redirect
– 在这里选择并加载模板。这是不退货的模板点。此后,模板无法更改。 -
…
-
the_post
– postdata 设置在这里,作为循环调用的一部分。这在模板中被调用,并且模板不会根据查询对象中的可用数据进行更改
最终编辑
And I’am claiming that while checks existence of posts, why should I run the same test twice. That is my question from first point I’ve been asking only about that.
而且,我终于明白了:一直以来,你的问题与 WordPress 或 WordPress Loop 无关。您正在询问将任意 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
条件包装器有很多用途,if
条件包装器与 while
循环完全不同。
次佳解决方案
改进芯片的答案真的是不可能的,只是为了减少追逐:
如果您想在没有帖子时显示不同的东西,请使用 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;
参考文献
注:本文内容整合自 google/baidu/bing 翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:gxnotes#qq.com(#替换为 @) 。