一个页面跑两次循环:rewind_posts 与多循环

作者: admin 分类: wordpress主题制作教程 发布时间: 2026-11-06 18:30

一个解释不通的现象

上一篇说过,caogenbj 的 single.php 原本有两个循环:一个输出作者,一个输出正文。

按理说,第一个循环跑完,主查询的指针就到头了。第二个循环的 have_posts() 应该返回假,正文应该不显示。

但页面上正文明明是正常的。为什么?

因为 have_posts() 会自动“倒带”

我翻 WordPress 源码,找到了答案。have_posts() 里有一段:

if ( $this->current_post + 1 < $this->post_count ) {
    return true;
} elseif ( $this->current_post + 1 == $this->post_count && $this->post_count > 0 ) {
    do_action_ref_array( 'loop_end', array( &$this ) );
    $this->rewind_posts();   // ← 关键:读到最后一条时,自动倒带
}
return false;

注意那句 rewind_posts():当指针走到最后一条时,have_posts() 会先把指针倒回开头,再返回假。

所以你看到的现象是:

  • 第一个循环:have_posts() 真 → the_post() → 输出作者 → 再 have_posts() 假(但内部已经倒带);
  • 第二个循环:have_posts() 又变真了(因为倒带了)→ the_post() → 输出正文。

两次循环都能跑,靠的是这个“自动倒带”。

但这是“靠容错在跑”

这个机制本来是为了方便(比如你想在同一个页面里重复遍历),但它也掩盖了错误写法。

问题在哪?

  1. 可读性:谁看到两个循环都会愣一下,不知道为什么要这么写;
  2. 脆弱:只要中间插一个别的查询(比如“相关文章”),$wp_query 被换掉,第二次循环就读到别的东西了;
  3. 性能:多跑一次循环,虽然不重新查库,但多了判断开销。

所以我这次重构,把两个循环合并成一个,问题就消失了。

什么时候真的需要“多次循环”

有一种情况确实需要:你查了一组文章,想把它们分两段输出(比如前 3 篇大图,后面小图列表)。

做法是用 rewind_posts() 手动倒带:

<?php
$q = new WP_Query( array( 'posts_per_page' => 9 ) );

// 第一段:前 3 篇
$i = 0;
while ( $q->have_posts() ) {
    $q->the_post();
    if ( $i < 3 ) { /* 大图 */ }
    $i++;
}
$q->rewind_posts();   // 倒带

// 第二段:全部 9 篇
while ( $q->have_posts() ) {
    $q->the_post();
    /* 小图列表 */
}
wp_reset_postdata();
?>

注意:这里用的是自己的 WP_Query,不是主查询。rewind_posts() 是它自己的方法,倒带的是它自己。

关键区别:主查询 vs 自定义查询

主查询($wp_query)是 WordPress 自动帮你查的;自定义查询(new WP_Query)是你自己 new 出来的。

两者都有 rewind_posts(),但混着用就会出事:你倒带了主查询,可能影响别的模板逻辑;你倒带了自己的查询,主查询不受影响。

所以规则是:自己的查询,自己倒带;不要动主查询。

小结

一句话记住:have_posts() 走到头会自动倒带,所以“两次循环”能跑,但那是靠容错;正确做法是一个循环包完,需要多次遍历就用自定义 WP_Query + rewind_posts。

下一篇讲一个更常见的坏习惯:query_posts 为什么不能用。

本系列导航

相关文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Powered by 草根站长笔记 © 2015-2026 草根站长笔记 Inc.版权所有,禁止转载