每周获取最新的 Wordpress 资源

如何写多个循环只查询一次数据库

我是 WP_Query 类的超级粉丝:我在许多客户的站点使用它自定义查询并输出内容。

如果你想要在同一个页面运行多个循环,最简单的方法就是当你需要一个循环的时候就运行一次 WP_Query。但是这样有个缺点:Wordpress 每次运行一次查询时,它都会向数据库发送一次请求,这个是花费时间的,会让你的站点变慢。并且如果你使用 WP_Query 来代替主查询输出内容,那么这就会让主查询变得冗余,这又是浪费资源。

这里我将展示如何运行多个循环,只查询一次。你可以使用主查询或者使用和 WP_Query 相同的技术。

这篇文章共分三个部分:

  • 创建一个子主题和一个模板文件。
  • 为循环内容创建一个 template part(模板部件)。
  • 创建多个循环。

好了,让我们开始吧!

开始之前你需要什么

如果要跟着做的话,你需要:

  • 一个安装好的开发用的 WordPress 站点。
  • 一个代码编辑器。
  • 站点的文章和分类测试数据已经准备好 —— 我使用的是 WordPress 主题单元测试数据
  • twenty sixteen 主题已经安装。
  • twenty sixteen 的子主题已经安装并且激活 —— 我将简单介绍如何设置子主题。

你不用必须使用 twenty sixteen 和它的子主题 —— 你可以在自己的主题上使用这个技术。但是我将使用 twenty sixteen 做演示。

创建子主题

首先让我们先创建 twenty sixteen 的子主题。这样做是因为我不想编辑 twenty sixteen 主题本身。

wp-content/themes 文件夹里创建一个新的空文件夹,命名为 wordpresshi-one-query-multiple-loops

在那个文件夹里, 创建一个叫 style.css 的文件并且把一下这个添加进去:

/*
Theme Name:     WordPressHi One Query Multiple Loops
Theme URI:      http://www.wordpresshi.com/one-query-multiple-loops/
Description:    Theme to support Tutorial on running multiple loops while querying the database just once. Child theme for the Twenty Sixteen theme.
Author:         WordPress Hi
Author URI:     http://www.wordpresshi.com/
Template:       twentysixteen
Version:        1.0
*/
 
@import url("../twentysixteen/style.css");

现在保存这个文件并且激活你的新主题。

下一步就是为分类创建一个模板文件。

从 twenty sixteen 主题中复制一个 archive.php 文件到你的新主题中去。不要移动它,而是复制它。把它重命名为 category.php。这个现在就是你站点的分类模板文件。

创建一个新的 Template Part(模板部件) 文件

第一步就是在我们的主题中创建一个 template part(模板部件) 文件,这个文件包含一个修改过的循环(来自 twenty sixteen 主题)。

在你的主题文件夹中,建一个子文件夹,命名为 includes。在这个子文件夹里,建一个新文件,命名为 loop-category.php

现在打开 twenty sixteen 主题中 template-parts/content.php 这个文件并且找到这个段代码:

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <header class="entry-header">
        <?php if ( is_sticky() && is_home() && ! is_paged() ) : ?>
            <span class="sticky-post"><?php _e( 'Featured', 'twentysixteen' ); ?></span>
        <?php endif; ?>
 
        <?php the_title( sprintf( '<h2 class="entry-title"><a href="%s" rel="bookmark">', esc_url( get_permalink() ) ), '</a></h2>' ); ?>
    </header><!-- .entry-header -->
 
    <?php twentysixteen_excerpt(); ?>
 
    <?php twentysixteen_post_thumbnail(); ?>
 
    <div class="entry-content">
        <?php
            /* translators: %s: Name of current post */
            the_content( sprintf(
                __( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'twentysixteen' ),
                get_the_title()
            ) );
 
            wp_link_pages( array(
                'before'      => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentysixteen' ) . '</span>',
                'after'       => '</div>',
                'link_before' => '<span>',
                'link_after'  => '</span>',
                'pagelink'    => '<span class="screen-reader-text">' . __( 'Page', 'twentysixteen' ) . ' </span>%',
                'separator'   => '<span class="screen-reader-text">, </span>',
            ) );
        ?>
    </div><!-- .entry-content -->
 
    <footer class="entry-footer">
        <?php twentysixteen_entry_meta(); ?>
        <?php
            edit_post_link(
                sprintf(
                    /* translators: %s: Name of current post */
                    __( 'Edit<span class="screen-reader-text"> "%s"</span>', 'twentysixteen' ),
                    get_the_title()
                ),
                '<span class="edit-link">',
                '</span>'
            );
        ?>
    </footer><!-- .entry-footer -->
</article><!-- #post-## -->

把这段代码复制到你的新文件中。

编辑 Template Part

这个 twenty sixteen 的循环不能达到分类归档页的要求,所以我将会对它做修改。还有我想要显示的是摘要,而不是全部内容,这里我们会删除那个部分。

在你的 loop-category.php 文件中,找到这个代码并且删除它:

<div class="entry-content">
    <?php
        /* translators: %s: Name of current post */
        the_content( sprintf(
            __( 'Continue reading<span class="screen-reader-text"> "%s"</span>', 'twentysixteen' ),
            get_the_title()
        ) );
 
        wp_link_pages( array(
            'before'      => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentysixteen' ) . '</span>',
            'after'       => '</div>',
            'link_before' => '<span>',
            'link_after'  => '</span>',
            'pagelink'    => '<span class="screen-reader-text">' . __( 'Page', 'twentysixteen' ) . ' </span>%',
            'separator'   => '<span class="screen-reader-text">, </span>',
        ) );
    ?>
</div><!-- .entry-content -->

另外一步就是把函数 twenty_sixteen_excerpt() 替换成标准的 the_excerpt() 函数,这是由于 twenty sixteen 这个版本不包含全文链接。

找到这一行:

<?php twenty_sixteen_excerpt(); ?>

替换成:

<?php the_excerpt(); ?>

我们也需要对标题标签做一点点修改。

在这个 template part(模板部件) 里,编辑这行:

<?php the_title( sprintf( '<h2 class="entry-title"><a href="%s" rel="bookmark">', esc_url( get_permalink() ) ), '</a></h2>' ); ?>

h2 标签改为 h3

<?php the_title( sprintf( '<h3 class="entry-title"><a href="%s" rel="bookmark">', esc_url( get_permalink() ) ), '</a></h3>' ); ?>

保存 template part(模板部件)文件。现在回到 category.php 文件继续进行。

创建我们的 Loop

首先让我们移除 category.php 文件里 twenty sixteen 里引用的 template part(模板部件)部分,然后用上面我们的新文件替代。

在 category.php 文件中找到这个代码:

get_template_part( 'template-parts/content', get_post_format() );

删除它。

现在我们将创建多个循环。

在这个例子中我们首先列出标签为 'content' 的所有文章,使用 has_tag() 这个条件标签。

这个意味着我要运行三个循环:

  • 第一个检查查询是否返回了带有这个标签的文章。
  • 如果是,第二个输出带这个标签的文章。
  • 第三个输出不带这个标签的文章。

在这些循环的中间,我将使用 rewind_posts() 来重置文章,而不用重设查询:我们每次仍然使用主查询。

第一个 Loop:检查文章

在你的 category.php 文件中,找到循环开始的地方:

while ( have_posts() ) : the_post();

在这行的上面,定义一个新的变量,命名为 $count

$count = 0;

在那个循环里面, 添加这段代码:

// check if there are any posts with the '' tag
$tag = 'content';
if ( has_tag( $tag ) ) {
    $count +=1;
}

这个将会检查文章是否有 'content' 这个标签,如果有的话,然后会给 count 加上 1。

你的循环看起来会像这样:

// Check for posts in the first loop.
$count = 0;
while ( have_posts() ) : the_post();
 
// check if there are any posts with the '' tag
$tag = 'content';
if ( has_tag( $tag ) ) {
    $count +=1;
}
     
endwhile;

第二个循环:用标签输出文章

下一步是运行一个循环来输出带这个标签的文章,当然前提是有这样的文章,也就是 $count 值大于 0

在你的循环 之后添加这段代码:

if ( $count > 0 ) {
                     
    rewind_posts();
 
    echo '<h2>Posts tagged with ' . $tag . '</h2>';
     
    while ( have_posts() ) : the_post();
     
    if ( has_tag( $tag ) ) {            
        get_template_part( 'includes/loop', 'category');    
    }
    
    // End the loop.
    endwhile;
     
}

这个检验 $count 的值是否大于零,如果是,那么重置文章,然后再次运行循环。每一篇文章它都会检查是否有我们的标签,如果有,它就会调用我们刚创建的模板。

第三个循环:输出剩下来的文章

最后一个循环输出剩余的文章。即是没有 'content' 标签的所有文章。

在你第二个循环的下面,添加这个:

rewind_posts();
         
// Second Loop - posts not with the 'content' tag
while ( have_posts() ) : the_post();
         
    if ( !has_tag( $tag ) ) {           
        get_template_part( 'includes/loop', 'category');    
    }
         
// End the loop.
endwhile; ?>

这段代码重置文章,然后再次运行循环。这次是检测那些没有 'content' 标签的所有文章,并且使用我们的 template part(模板部件)输出。

好了,接下来就回到分类归档页面,然后查看下是否正确输出吧。

总结

从一次查询运行多个循环并不复杂,你可以使用 rewind_posts() 来回倒查询,然后再次运行,而不是重置查询,再去创建一个新的。同时,你可以使用条件标签来自定义哪些文章输出,而不是定义新的查询参数。

重要注意事项:当你实现这些时,不要尝试使用 query_posts() 来修改主查询。因为这样会让你的网站变慢,甚至比使用多个查询还要慢。

在这个例子里我们给予主查询运行着两个循环,避免了使用 WP_Query 来运行两个额外的查询,这减少了服务器负载。通过使用 WP_Query 或者主查询做一条你定义的查询,你可以在其他归档页面应用这项技术。

You May Also Like

About the Author: ted

发表评论

电子邮件地址不会被公开。 必填项已用*标注