caogenbj 的 single.php(文章页)里,有一段我一直没看懂的代码:
<span>作者: <?php while (have_posts()) : the_post(); ?>
<?php the_author(); ?>
<?php endwhile; ?>
</span>
一个“作者”字段,为什么要套一层 while 循环?直接用 the_author() 不行吗?
后来我想明白了:原作者遇到了“循环外调标签不生效”的问题,于是用循环绕了过去。
文章页(single.php)加载的时候,WordPress 已经查到了这篇文章,但还没有把它设成“当前文章”。
也就是说,全局 $post 此时还不是这篇文章。你在这个位置直接调 the_author(),它读的是一个没设置好的 $post,结果可能是空的,或者读到上一篇文章。
原作者的做法是:先跑一遍循环,让 the_post() 把 $post 设置好,再输出作者。所以有了那个看起来多余的 while。
这个循环虽然能让作者显示出来,但它有两个问题:
$post 设好了——顺序上“碰巧对了”,但很脆弱。标准做法是:用一个循环把整块内容包起来,标题、作者、分类、正文全在循环里面。
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<h1><?php the_title(); ?></h1>
<span>作者: <?php the_author(); ?></span>
<span>分类: <?php the_category(','); ?></span>
<span>时间: <?php the_time('Y-m-d'); ?></span>
<div><?php the_content(); ?></div>
<?php endwhile; endif; ?>
这样 $post 在循环里只被设置一次(单篇文章就一条),后面所有标签都读它,不用再套小循环。
这次重构,我把 caogenbj 的 single.php 改成了上面那种结构:
改完之后,代码短了,逻辑也直了:一个页面只跑一个循环,所有标签都在循环里读同一个 $post。
以后你写模板,看到下面这种情况,基本可以判定“有问题”:
while ( have_posts() );the_title()、the_content() 出现在任何 while 之外;这三种,都是在“跟 $post 的指针较劲”。正确的做法永远是:用一个循环把要读的内容包住。
一句话记住:循环外调模板标签,读的是一个没设置好的 $post;正确做法是用一个循环把整块内容包起来,别用小循环“凑”。
下一篇讲一个更奇怪的现象:一个页面跑两次循环,为什么第二次还能读到文章?