The Loop 是 WordPress 用于通过主题的模板文件输出帖子的默认机制。检索多少篇帖子由“阅读设置”中定义的每页显示的帖子数量决定。在 The Loop(循环)内部,WordPress 会获取当前页面要显示的每个帖子,并根据您主题的指示对其进行格式化。

The Loop 从 WordPress 数据库中提取每个帖子的数据,并将适当的信息插入到每个模板标签的位置。The Loop(循环)中的任何 HTML 或 PHP 代码都将针对每篇帖子进行处理。

简单地说,Loop 名副其实:它一次遍历为当前页面检索到的每个帖子,并执行您主题中指定的操作。

The Loop 可用于多种不同的用途,例如:

  • 在博客主页上显示文章标题和摘要;
  • 在一篇单篇文章上显示内容和评论;
  • 使用模板标签在独立页面上显示内容;以及
  • 显示来自自定义帖子类型和自定义字段的数据。

您可以在各个模板文件中定制 Loop,以显示和操作不同的内容。

The Loop 详解

基本循环如下:

<?php
if ( have_posts() ) :
    while ( have_posts() ) : the_post();
        // Display post content
    endwhile;
endif;
?>

这个循环表示:如果有帖子,则遍历并显示这些帖子。分解得更详细:

  • have_posts() 函数检查是否有任何帖子。
  • 如果有帖子,while循环会持续执行,只要括号中的条件在逻辑上为真。只要 have_posts() 继续为真,循环就会继续。

使用 The Loop

The Loop 应放置在index.php中,以及任何用于显示帖子信息的模板中。因为您不想重复调用头部多次,所以循环应该始终放在对 get_header()的调用之后。例如:

<?php
get_header();
if ( have_posts() ) :
    while ( have_posts() ) : the_post();
        // Display post content
    endwhile;
endif;
?>

在上述示例中,循环的结束由 endwhile 和endif表示。循环必须始终以上面提到的相同 if 和 while语句开始,并以相同的结束语句结束。

您希望应用于所有帖子的任何模板标签都必须存在于起始和结束语句之间。

您可以包含一个自定义的 404“未找到”消息,如果找不到符合指定条件的帖子时将显示该消息。该消息必须放置在 endwhile 和endif 语句之间,如下面的示例所示。

一个极其简单的 index.php文件看起来像这样:

<?php
get_header();

if ( have_posts() ) :
    while ( have_posts() ) : the_post();
        the_content();
    endwhile;
else :
    _e( 'Sorry, no posts matched your criteria.', 'textdomain' );
endif;

get_sidebar();
get_footer();
?>

The Loop 可以显示什么

The Loop 可以为每个帖子显示多种不同的元素。例如,许多主题中使用的一些常见模板标签是:

  • next_post_link() – 链接到按时间顺序在当前帖子之后发布的帖子
  • previous_post_link() – 链接到按时间顺序在当前帖子之前发布的帖子
  • the_category() – 与正在查看的帖子或页面关联的分类目录
  • the_author() – 帖子的作者或页面的作者
  • the_content() – 帖子或页面的主要内容
  • the_excerpt() – 帖子的主要内容的第一个 55 个单词,后跟省略号 (…) 或指向完整帖子的“阅读更多”链接。您还可以使用帖子的“摘要(Excerpt)”字段来自定义特定摘要的长度。
  • the_ID() – 帖子或页面的 ID
  • the_meta() – 与帖子或页面关联的自定义字段
  • the_shortlink() – 使用站点 URL 和帖子或页面的 ID 链接到该页面或帖子的链接
  • the_tags() – 与帖子关联的标签(tag)
  • the_title() – 帖子或页面的标题
  • the_time() – 帖子的时间或日期。这可以使用标准的 PHP date 函数格式进行自定义。

您还可以使用条件标签,例如:

  • is_home() – 如果当前页面是主页则返回 true
  • is_admin() – 如果在管理屏幕内则返回 true,否则为 false
  • is_single() – 如果页面当前正在显示单篇帖子则返回 true
  • is_page() – 如果页面当前正在显示单个页面则返回 true
  • is_page_template() – 可用于确定页面是否使用特定模板,例如:is_page_template('about-page.php')
  • is_category() – 如果页面或帖子具有指定的分类目录则返回 true,例如:is_category('news')
  • is_tag() – 如果页面或帖子具有指定的标签(tag)则返回 true
  • is_author() – 如果在作者的存档页面内则返回 true
  • is_search() – 如果当前页面是搜索结果页面则返回 true
  • is_404() – 如果当前页面不存在则返回 true
  • has_excerpt() – 如果帖子或页面有摘要(excerpt)则返回 true

示例

让我们看看一些 The Loop 实际运行的例子:

基本示例

博客存档(Blog Archive)

大多数博客都有一个博客存档页面,它可以显示多种内容,包括帖子标题、缩略图和摘要。下面的示例显示了一个简单的循环,它会检查是否有任何帖子,如果有,则输出每个帖子的标题、缩略图和摘要。如果没有帖子存在,它将显示括号中的消息。

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

独立帖子

在 WordPress 中,每个帖子都有自己的页面,该页面显示与该帖子相关的信息。模板标签允许您自定义要显示的哪些信息。

在下例中,循环输出帖子的标题和内容。您可以在帖子或页面的模板文件中使用此示例来显示关于帖子的最基本信息。您还可以定制此模板以向帖子添加更多数据,例如分类目录。

<?php
if ( have_posts() ) :
    while ( have_posts() ) : the_post();
        the_title( '<h1>', '</h1>' );
        the_content();
    endwhile;
else:
    _e( 'Sorry, no pages matched your criteria.', 'textdomain' );
endif;
?>

中级示例

以不同方式样式化某些分类目录中的帖子

下面的示例做了几件事:

  • 首先,它显示每个帖子的标题、时间、作者、内容和分类目录,类似于上面独立帖子的示例。
  • 接下来,它使得 ID 为“3”的分类目录中的帖子可以以不同方式样式化,利用 in_category()模板标签。

此示例中的代码注释提供了循环每个阶段的详细信息:

<?php
// Start the Loop.
if ( have_posts() ) :
    while ( have_posts() ) : the_post();
        /* * See if the current post is in category 3.
          * If it is, the div is given the CSS class "post-category-three".
          * Otherwise, the div is given the CSS class "post".
        */
        if ( in_category( 3 ) ) : ?>
        <div class="post-category-three">
        <?php else : ?>
        <div class="post">
        <?php endif; 

            // Display the post's title.
            the_title( '<h2>', ';</h2>' ); 

            // Display a link to other posts by this posts author.
            printf( __( 'Posted by %s', 'textdomain' ), get_the_author_posts_link() );

            // Display the post's content in a div.
            ?>
            <div class="entry">
                <?php the_content() ?>
             </div>

            <?php
            // Display a comma separated list of the post's categories.
            _e( 'Posted in ', 'textdomain' ); the_category( ', ' ); 

        // closes the first div box with the class of "post" or "post-cat-three"
       ?>
       </div>

    <?php
    // Stop the Loop, but allow for a "if not posts" situation
    endwhile; 

else :
    /*
      * The very first "if" tested to see if there were any posts to
      * display. This "else" part tells what do if there weren't any.
     */
     _e( 'Sorry, no posts matched your criteria.', 'textdomain' );

// Completely stop the Loop.
 endif;
?>

多个循环

在某些情况下,您可能需要使用不止一个循环。例如,您可能想在页面顶部的目录列表表中显示帖子的标题,然后在页面的更下方显示内容。由于查询未被更改,我们只需在需要第二次遍历帖子时重新绕回(rewind)循环即可。为此我们将使用 rewind_posts() 函数。

使用 rewind_posts

您可以使用rewind_posts()来第二次遍历相同的查询。如果您想在页面的不同位置显示相同的查询两次,这很有用。

这是 rewind_posts() 使用的示例:

<?php
// Start the main loop
if ( have_posts() ) :
    while ( have_posts() ) : the_post();
        the_title();
    endwhile;
endif;

// Use rewind_posts() to use the query a second time.
rewind_posts();

// Start a new loop
while ( have_posts() ) : the_post();
    the_content();
endwhile;
?>

创建次要查询和循环

使用两个具有相同查询的循环相对容易,但并不总是您所需要的。相反,您通常希望创建一个次要查询以在模板上显示不同的内容。例如,您可能想在同一页面上显示两组帖子,但对每组执行不同的操作。一个常见的例子如下所示:在一篇单篇文章下方显示来自同一分类目录的一组帖子。

<?php
// The main query.
if ( have_posts() ) :
    while ( have_posts() ) : the_post();
        the_title();
        the_content();
    endwhile;
else :
    // When no posts are found, output this text.
    _e( 'Sorry, no posts matched your criteria.' );
endif;
wp_reset_postdata();                                                        

/*
 * The secondary query. Note that you can use any category name here. In our example,
 * we use "example-category".
 */
$secondary_query = new WP_Query( 'category_name=example-category' );        

// The second loop.
if ( $secondary_query->have_posts() )
    echo '<ul>';
    while ( $secondary_query->have_posts() ) : $secondary_query->the_post();
        the_title( '<li>', '</li>' );
     endwhile;
     echo '</ul>';
endif;
wp_reset_postdata();
?>

正如您在上面的示例中看到的,我们首先显示一个常规循环。然后定义一个新变量,该变量使用 WP_Query 查询特定分类目录;在我们的例子中,我们选择了example-category的 slug。

请注意上面的示例中的常规循环有一个不同之处:它调用 wp_reset_postdata() 来重置帖子数据。在使用第二个循环之前,您需要重置帖子数据。有两种方法可以做到这一点:

  1. 通过使用rewind_posts()函数;或
  2. 通过创建新的查询对象。

重置多个循环

在模板中使用多个循环时,重置它们非常重要。如果不这样做,由于数据在全局 $post变量中的存储和使用方式,可能会导致意外结果。根据调用方式的不同,有三种主要方法可以重置循环。

使用 wp_reset_postdata

当您运行带有 WP_Query 的自定义或多个循环时,请使用wp_reset_postdata()。此函数将全局 $post变量恢复到主查询中的当前帖子。如果您遵循最佳实践,这是您重置循环最常用的函数。

要正确使用此函数,请在任何带有WP_Query的循环之后放置以下代码:

<?php wp_reset_postdata(); ?>

以下是使用 WP_Query 并使用 wp_reset_postdata()重置的循环示例。

 <?php
// Example argument that defines three posts per page.
$args = array( 'posts_per_page' => 3 ); 

// Variable to call WP_Query.
$the_query = new WP_Query( $args ); 

if ( $the_query->have_posts() ) :
    // Start the Loop
    while ( $the_query->have_posts() ) : $the_query->the_post();
        the_title();
        the_excerpt();
    // End the Loop
    endwhile;
else:
// If no posts match this query, output this text.
    _e( 'Sorry, no posts matched your criteria.', 'textdomain' );
endif; 

wp_reset_postdata();
?> 

使用 wp_reset_query

使用 wp_reset_query()将WP_Query和全局$post数据恢复到原始主查询。如果您在循环中使用query_posts(),您MUST(必须)使用此函数来重置您的循环。您可以将它用于带有 WP_Query的自定义循环之后,因为它实际上在运行时调用wp_reset_postdata()。然而,对于任何涉及 WP_Query 的自定义循环,最好使用wp_reset_postdata()。

query_posts()不是最佳实践,应尽可能避免。因此,您不应该有太多使用wp_reset_query()的理由。

要正确使用此函数,请在任何带有 query_posts()的循环之后放置以下代码。

<?php wp_reset_query(); ?>