掌握WP_Query—10个有用的例子

287 阅读5分钟

现在我们已经了解了关于WP_Query 类的几乎所有内容,现在是时候尝试一些例子了。在这一部分,我们将在10个不同的场景中利用WP_Query 类和相关函数。

这将是一个有趣的练习,我希望它同样具有教育意义。让我们开始吧!

关于用WP_Query创建循环的快速教程

作为复习,这里有一个关于用WP_Query 类创建WordPress循环的小型教程。

这与创建一个普通的循环没有什么不同,真的。一个典型的WordPress循环是这样的。

<?php

if ( have_posts() ) {
    while ( have_posts() ) {
        the_post();
        // Post data goes here.
    }
}

?>

而用WP_Query 类来创建一个循环,只有几个区别。

<?php

$args = array(
    'category_name' => 'news',
    'posts_per_page' => 3
);

$my_query = new WP_Query( $args );

if ( $my_query->have_posts() ) {
    while ( $my_query->have_posts() ) {
        $my_query->the_post();
        // Post data goes here.
    }
}

// Reset the `$post` data to the current post in main query.
wp_reset_postdata();

?>

让我们看看第二个例子中的区别。

  • 我们为我们的WP_Query 实例设置了一些参数
  • 我们实例化了WP_Query
  • 我们在have_posts()the_post() 函数的开头添加了$my_query-> (所以它们现在是WP_Query 类的方法)。
  • 我们重置了$post 的数据,这样它就可以返回到主查询。

现在我们知道了如何用WP_Query 创建一个循环,以及普通循环和用WP_Query 创建的循环之间的区别。我们不会在每个例子中都创建循环(为了保持教程的简短和主题),所以如果你需要用下面的例子创建一个循环,你可以参考本节。

例子1:一个作者在这一年里的所有帖子

假设你想在一个特殊的 "今年作者的文章"部分列出一个特定作者在今年写的文章。两个WP_Query 参数的简单组合就足够了。

<?php

// Get the year we're in.
$current_year = date( 'Y' );

// Setup arguments.
$args = array(
    // Get the author with the nicename "john".
    'author' => 'john',
    // Get his posts from this year.
    'year'   => $current_year
);

// Instantiate new query instance.
$my_query = new WP_Query( $args );

?>

在一个循环中传递这个查询,你就可以开始了!

例子 2: 这个类别的最新文章(除了当前的文章)

假设你想在每个帖子的单页下创建一个循环,并列出该帖子所在类别的最新帖子。当然,你必须排除当前的帖子,以防它可能是该类别的最新帖子之一。以下是你如何创建带有'cat''post__not_in' 参数的查询。

<?php

// Get the current post id.
$current_post_id = get_the_ID();

// Get the current post's category (first one if there's more than one).
$current_post_cats = get_the_category();
$current_post_first_cat_id = $current_post_cats[ 0 ]->term_id;

// Setup arguments.
$args = array(
    // Get category's posts.
    'cat' => $current_post_first_cat_id,
    // Exclude current post.
    'post__not_in' => array( $current_post_id )
);

// Instantiate new query instance.
$my_query = new WP_Query( $args );

?>

对于循环,我建议在帖子标题上方创建三或四列的帖子缩略图。它将在帖子下面和评论区之前看起来非常漂亮。

例子3:按评论数排列的最受欢迎的帖子

WordPress没有一个内置的帖子浏览计数系统,而提供这种功能的插件以拖慢网站速度而闻名(因为在每一个帖子浏览时,插件都要在数据库中反复写,以记录浏览计数)。然而,还有一种测量方法可以确定哪些帖子最受欢迎:计算评论。与浏览次数不同,评论次数已经在数据库中了--WP_Query 类使得按评论次数排列帖子变得非常容易。

<?php

// Setup arguments.
$args = array(
    // Order by comment count.
    'orderby' => 'comment_count'
);

// Instantiate new query instance.
$my_query = new WP_Query( $args );

?>

看看这有多简单?现在想象一下,创建一个带有循环的自定义页面模板,运行这个查询--最多评论的帖子 页面。

例子4:一个简单的滑块设置

当使用WordPress建立企业网站、作品集或网络杂志时,滑块已经成为一个必须的工业标准。我不太喜欢滑块(我认为它的用户体验不好),但网络似乎喜欢它,所以我在为我的客户制作网站时不能对他们说不。如果他们想要滑块,我使用一个简单的查询,使用WP_Query 类。

<?php

// Setup arguments.
$args = array(
    // Get the "slider" post type.
    'post_type' => 'slider',
    // Get a specific slider category.
    'category_name' => 'home-slides',
    // Get all slides and don't paginate.
    'nopaging' => true
);

// Instantiate new query instance.
$my_query = new WP_Query( $args );

?>

'cat' 参数可以用来检索不同类别的幻灯片,这样你就可以把幻灯片组分开,在多个页面上使用多个滑块。如果你打算在你的网站中只使用一个滑块,你可以删除这一行,就可以了。

例子5:边栏里的随机语录

如果你热衷于文学或宗教,你可能想在侧边栏里放一些你最喜欢的名言--如果你有目的地使用这个区域,就不会浪费空间了。因此,如果你要在每个页面浏览时在侧边栏中随机列出一句话,你可以使用下面的代码片段来创建帖子类型,并使用下面的查询来在侧边栏中创建一个循环。

<?php

/* 
 * Create new post type called "Quotes"
 * (refer to the `register_post_type` function to
 * learn more about creating custom post types).
 */
function quote_post_type() {
    
    $args = array(
        'label' => 'Quotes',
        'public' => true
    );
    
    register_post_type( 'quotes', $args );
}

add_action( 'init', 'quote_post_type' );

// Setup arguments.
$args = array(
    // Get the "quotes" psot type.
    'post_type' => 'quotes',
    // Randomize the order.
    'orderby' => 'rand',
    // Get only one item.
    'posts_per_page' => 1,
);

// Instantiate new query instance.
$my_query = new WP_Query( $args );

?>

一个简单而优雅的解决方案。

例子6:在一个价格范围内列出产品

我在Scribu.net上发现了这个例子,我必须说,它可能是本教程中最好的WP_Query 。它也比其他的更有技术性,因为在这种情况下,它可以应用于由WordPress驱动的电子商务网站。

如果你想从一个自定义的产品帖子类型中列出项目,并使用价格自定义字段过滤结果,你将使用以下代码片段。

<?php

// Source: https://scribu.net/wordpress/advanced-metadata-queries.html

// Setup arguments.
$args = array(
    // Get the "product" post type.
    'post_type' => 'product',
    // Setup the "meta query".
    'meta_query' => array(
        array(
            // Get the "price" custom field.
            'key' => 'price',
            // Set the price values.
            'value' => array( 100, 200 ),
            // Set the compare operator.
            'compare' => 'BETWEEN',
            // Only look at numeric fields.
            'type' => 'numeric',
        )
    )
);

// Instantiate new query instance.
$my_query = new WP_Query( $args );

?>

衷心感谢Silviu-Cristian Burca!

例子 7: 嵌入帖子的短代码

这里有一个有趣的练习--我们也可以使用Shortcode API!在这个例子中,我们将创建一个短码,可以在一个帖子中嵌入一个帖子。[postception](在下面的代码中,我们创建了一个短码函数,允许我们嵌入帖子(或任何自定义帖子类型),并让我们选择是否显示完整的帖子或只是一个摘录。

<?php

/*
 * Usage:
 *
 * [embed_post slug="my-post"]
 * [embed_post slug="my-post" full="false"]
 * [embed_post type="movie" slug="inception"]
 */

function tutsplus_embedded_post_shortcode( $attributes ) {

    // Extract shortcode attributes.
    extract(
        shortcode_atts(
            array(
                'type' => 'post',
                'slug' => '',
                'full' => true
            ),
            $attributes
        )
    );

    // Setup arguments.
    $args = array(
        // Get post type ("post" by default).
        'post_type' => $type,
        // Get post by slug.
        'name' => $slug
    );

    // Instantiate new query instance.
    $my_query = new WP_Query( $args );

    // Check that we have query results.
    if ( $my_query->have_posts() ) {

        // Begin generating markup.
        $output = '<section class="embedded-post">';

        // Start looping over the query results.
        while ( $my_query->have_posts() ) {

            $my_query->the_post();

            // Add title to output.
            $output .= '<h2 class="embedded-post-title">';
                $output .= get_the_title();
            $output .= '</h2>';

            // Get full post if `$full` is true, otherwise, show the get excerpt
            if ( 'true' === $full ) {

                // Add full content to output.
                $output .= '<div class="embedded-post-content">';
                    $output .= get_the_content();
                $output .= '</div>';

            } else {

                // Add excerpt to output.
                $output .= '<div class="embedded-post-excerpt">';
                    $output .= get_the_excerpt();
                    $output .= '&hellip; <a href="' . get_permalink() . '">' . __( 'See full post', 'tutsplus' ) . ' &raquo;</a>';
                $output .= '</div>';

            }

        }

        // End generating markup.
        $output .= '</section>';

    } else {

        // Output message to let user know that no posts were found.
        $output = '<section class="embedded-post-error">';
            $output .= '<p>' . __( 'No posts found.', 'tutsplus' ) . '</p>';
        $output .= '</section>';

    }

    wp_reset_postdata();

    return $output;

}

add_shortcode( 'embed_post', 'tutsplus_embedded_post_shortcode' );

?>

例子 8: 当前预定的帖子列表(可选择摘录)

这里有一个想法。你为什么不向你的访问者展示一些即将发布的帖子的偷拍内容呢?你可以使用下面的功能来列出你预定的帖子,在标题后面加上或不加上摘录。

<?php

/*
 * Usage with Excerpts:
 * <?php echo tutsplus_show_drafts(); ?>
 *
 * Usage without Excerpts:
 * <?php echo tutsplus_show_drafts( false ); ?>
 */

function tutsplus_show_drafts( $show_excerpts = true ) {

    // Setup arguments.
    $args = array(
        'post_status' => 'future',
        'nopaging' => true
    );

    // Instantiate new query instance.
    $my_query = new WP_Query( $args );

    // Check that we have query results.
    if ( $my_query->have_posts() ) {

        // Begin generating markup.
        $output = '<section class="pending-posts">';

        // Start looping over the query results.
        while ( $my_query->have_posts() ) {

            $my_query->the_post();

            // Output draft post title and excerpt (if enabled).
            $output .= '<div class="pending">';
                $output .= '<h3 class="pending-title">' . get_the_title() . '</h3>';
                    $output .= get_the_title();
                $output .= '</h3>';

                if ( $show_excerpts ) {

                    $output .= '<div class="pending-excerpt">';
                        $output .= get_the_excerpt();
                    $output .= '</div>';

                }

            $output .= '</div>';

        }

        // End generating markup.
        $output .= '</section>';

    } else {

        // Let user know that nothing was found.
        $output = '<section class="drafts-error">';
            $output .= '<p>' . __( 'Nothing found', 'tutsplus' ) . '</p>';
        $output .= '</section>';

    }

    wp_reset_postdata();

    return $output;

}

?>

例子9:一年前的文章今天发布

如果你的博客超过一年,而且你的内容是永恒的(意味着2015年和2025年的人都能找到相关的文章),添加一个 "一年前的今天"部分可能会提高你的页面浏览量。以下是你如何做的。

<?php

// Setup arguments.
$args = array(
    // Day (1 - 31).
    'day' => date( 'j' ),
    // Month (1 - 12).
    'monthnum' => date( 'n' ),
    // Year (minus 1).
    'year' => date( 'Y' ) - 1,
    // Show only one post.
    'posts_per_page' => 1
);

// Instantiate new query instance.
$my_query = new WP_Query( $args );

?>

使用这个查询来建立一个循环,显示过去的一篇文章。

例子 10: 显示当前页面的子页面

除了子页面的标题,你没有其他东西可以放在你的服务我们的作品我的作品集页面内?也许有一段介绍,但你是对的,这些页面注定是占位符。不过,把子页面放在里面也是一个好主意--也许是一个带有方形缩略图的网格,下面是标题。让我们看看在创建这样的页面模板时,我们应该使用哪些查询。

<?php

$current_page_id = get_the_ID();

// Setup arguments.
$args = array(
    // Get children of current page.
    'parent' => $current_page_id,
    // Disable pagination.
    'nopaging' => true
);

// Instantiate new query instance.
$my_query = new WP_Query( $args );

?>

关于WP_Query,需要记住的关键点

WP_Query 类在你的WordPress网站上循环浏览帖子数据时给你很大的权力。它有很多选项来帮助你缩小你想输出的帖子列表。然而,有几件事你应该牢记在心。

主查询与次要查询

在WordPress有两种类型的查询。第一种是当你访问一个网页时,WordPress通过分析你要访问的URL而自动运行的。这就是主查询。请记住,主查询不一定是被WordPress执行的第一个查询。除了WordPress根据请求的URL创建的查询外,所有其他类型的查询都是辅助查询。二级查询的例子是我们在前面的章节中创建的查询。

运行查询后重新设置数据

你应该在运行你的自定义或二级查询后,总是调用wp_reset_postdata() 函数。这个函数将恢复全局$post 变量的值,使其包含关于主帖的信息。换句话说,它基本上将模板标签的上下文从二级查询循环恢复到主查询循环。

还有一个类似于wp_reset_postdata() 的函数,叫做wp_reset_query() 。这两者之间的区别是,后者的函数将主查询重置为原始的主查询,然后调用wp_reset_postdata()

只有当你在代码中某处使用了query_posts() 函数时,你才需要调用wp_reset_query() 。然而,你应该避免在主题或插件中调用query_posts() 函数,因为这个函数会改变你的主查询。

改变主查询

如果你想对主查询进行修改怎么办?你应该通过使用pre_get_posts ,然后使用is_main_query() ,以确保你是在处理主查询。下面是一个例子。

<?php

function search_blacklist($query) {
    if ( ! is_admin() && $query->is_main_query() && $query->is_search()) {
        $query->set( 'post__not_in', array( 218 ) );
    }
}
add_action( 'pre_get_posts', 'search_blacklist' );

?>

这里我们使用pre_get_posts 钩子来执行一个函数,这个函数将阻止具有特定id的帖子出现在搜索结果中。你可以编写上述函数的变体,将搜索结果限制在一个特定的日期或类别等。

总结

我希望你和我在准备这些例子时一样喜欢它们。我特别注意给出不同的例子,既是为了好玩,也是为了激发你的创造力。

如果你在阅读这些例子时想到了更好的例子,或者有问题,不要犹豫,请在下面留言。如果你喜欢这篇文章,别忘了与你的朋友分享它

在下一部分中,我们将讨论WP_User_Query ,它是WP_Query 的姐妹类之一。届时见!