下面我将从基础到高级,全面地为你解析 WordPress 查询模板。

wordpress 查询模板
(图片来源网络,侵删)

核心查询函数:WP_Query

WP_Query 是 WordPress 中最强大、最灵活的查询函数,几乎所有的自定义查询都依赖于它。

基本语法结构

一个基本的 WP_Query 循环通常遵循以下模式:

<?php
// 1. 定义查询参数
$args = array(
    'post_type'      => 'post',
    'posts_per_page' => 5,
    'category_name'  => 'news',
);
// 2. 创建新的查询实例
$the_query = new WP_Query( $args );
// 3. 开始查询循环 (如果找到文章)
if ( $the_query->have_posts() ) :
    while ( $the_query->have_posts() ) : $the_query->the_post();
        // 循环内的代码:显示文章标题、内容等
        ?>
        <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
        <div><?php the_excerpt(); ?></div>
        <?php
    endwhile;
else :
    // 如果没有找到文章,显示提示信息
    echo '<p>抱歉,没有找到相关文章。</p>';
endif;
// 4. 重置文章数据 (非常重要!)
wp_reset_postdata();
?>

关键步骤解析

  1. 定义参数 ($args): 这是你告诉 WordPress “我想要什么内容” 的地方,通过一个关联数组来设置各种查询条件。
  2. 创建实例 (new WP_Query): 你将参数传递给 WP_Query 类,它会根据这些参数去数据库查询,并将结果存储在 $the_query 对象中。
  3. have_posts(): 这个方法检查查询结果中是否还有文章可以显示,类似于 while 循环的判断条件。
  4. the_post(): 这个方法会设置当前循环的文章数据,并让模板标签(如 the_title(), the_content())能够正确显示当前文章的内容。
  5. wp_reset_postdata(): 这是至关重要的一步! 当你使用自定义查询后,它会改变 WordPress 的全局 $post 变量,如果不重置,后续的模板(如页脚、侧边栏)可能会使用到错误的文章数据,这个函数会将全局 $post 恢复到主查询的状态。

常用查询参数 ($args 数组)

WP_Query 的强大之处在于其丰富的参数,下面是一些最常用的参数分类:

文章参数

参数 说明
p 123 (文章 ID) 根据文章 ID 查询。
name 'hello-world' (文章 slug) 根据文章的 slug (URL 友好名称) 查询。
page_id 7 (页面 ID) 根据页面 ID 查询。
pagename 'about' (页面 slug) 根据页面的 slug 查询。
post_type 'post', 'page', 'product' 查询指定类型的文章,可以是字符串或数组。
post_status 'publish', 'draft', 'pending' 查询指定状态的文章。
posts_per_page 5 每页显示的文章数量。-1 表示显示所有。
offset 3 跳过前面的 N 篇文章。
ignore_sticky_posts true 忽略置顶文章,将它们视为普通文章。

示例:查询 ID 为 123 的文章

wordpress 查询模板
(图片来源网络,侵删)
$args = array( 'p' => 123 );

分类和标签参数

参数 说明
cat 5 (分类 ID) 根据分类 ID 查询。
category_name 'news' (分类 slug) 根据分类的 slug 查询。
tag 'technology' (标签 slug) 根据标签的 slug 查询。
tag_id 32 (标签 ID) 根据标签 ID 查询。
tax_query (数组) 最强大的分类法查询,可以组合多个复杂的条件。

示例:查询 "新闻" 分类下的 5 篇文章

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

排序和分页参数

参数 说明
orderby 'date', 'title', 'rand', 'comment_count' 排序依据。
order 'DESC', 'ASC' 排序顺序,降序或升序。
paged 2 获取第几页的结果,与分页配合使用。

示例:随机显示 3 篇文章

$args = array(
    'posts_per_page' => 3,
    'orderby'        => 'rand',
);

高级参数:tax_query (分类法查询)

tax_query 是一个二维数组,让你可以构建极其复杂的查询,同时属于 A 和 B 分类”或“属于 A 分类但不属于 B 分类”。

示例1:查询同时属于 “新闻” 和 “科技” 这两个分类的文章

wordpress 查询模板
(图片来源网络,侵删)
$args = array(
    'post_type' => 'post',
    'tax_query' => array(
        'relation' => 'AND', // 关系:AND (同时满足) 或 OR (满足其一)
        array(
            'taxonomy' => 'category', // 分类法名称
            'field'    => 'slug',     // 根据 slug 查询
            'terms'    => 'news',     // 分类 slug
        ),
        array(
            'taxonomy' => 'category',
            'field'    => 'slug',
            'terms'    => 'technology',
        ),
    ),
);

示例2:查询属于 “新闻” 分类,但不属于 “视频” 子分类的文章

$args = array(
    'post_type' => 'post',
    'tax_query' => array(
        'relation' => 'AND',
        array(
            'taxonomy' => 'category',
            'field'    => 'slug',
            'terms'    => 'news',
        ),
        array(
            'taxonomy' => 'category',
            'field'    => 'slug',
            'terms'    => 'video',
            'operator' => 'NOT IN', // 操作符:NOT IN (不包含)
        ),
    ),
);

其他查询函数

除了 WP_Query,WordPress 还提供了一些更简单的函数,用于特定场景。

get_posts()

这是 WP_Query 的一个轻量级封装,用法几乎一样,但它默认不设置全局 $post 数据,因此循环中不能直接使用 the_title() 等模板标签,而应该使用 get_the_title() 等带 get_ 前缀的函数。

适用场景:当你只需要获取文章数据,但不需要在页面上直接显示时(作为数据源传给 JavaScript)。

$args = array( 'numberposts' => 10, 'category' => 4 );
$recent_posts = get_posts( $args );
foreach( $recent_posts as $post ) : setup_postdata($post); // 如果需要使用 the_ 系列标签,需要 setup_postdata
    ?>
    <div>
        <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
    </div>
    <?php
endforeach;
wp_reset_postdata();

query_posts()

⚠️ 强烈不建议使用!

这是一个历史遗留函数,它会直接修改和劫持主页的主查询,这会导致很多不可预知的问题,破坏 WordPress 的主查询逻辑,并可能影响性能和 SEO。

正确做法:如果你想在主页上修改默认查询,请使用 pre_get_posts 这个钩子。


使用 pre_get_posts 修改主查询

这是在 WordPress 主题中修改默认查询(如首页、分类页、搜索页)的最佳实践

适用场景

  • 在首页排除某个分类。
  • 在搜索结果中只显示某种文章类型。
  • 修改归档页的排序方式。

示例:让首页不显示 "私密" 分类下的文章

将以下代码添加到你的主题的 functions.php 文件中:

function exclude_category_from_homepage( $query ) {
    // is_home() 检查是否是首页,is_main_query() 确保只修改主查询
    if ( $query->is_home() && $query->is_main_query() ) {
        // 'cat' => '-1' 中的 -1 表示排除 ID 为 1 的分类
        $query->set( 'cat', '-1' ); // 将 'cat' 参数设置为 -1
    }
}
add_action( 'pre_get_posts', 'exclude_category_from_homepage' );

工作原理

  1. pre_get_posts 钩子在查询执行之前触发。
  2. 我们通过 $query->is_home() 判断当前是否是首页。
  3. $query->is_main_query() 确保我们只修改 WordPress 的主要查询,而不是我们自定义的 WP_Query 循环。
  4. $query->set( 'cat', '-1' ) 直接修改即将执行的查询参数,将其 cat 值设为 -1(排除 ID 为 1 的分类)。
  5. 这样,当 WordPress 执行首页的主查询时,就会自动排除该分类下的文章。

最佳实践与性能优化

  1. 总是重置数据:在使用完 WP_Query 后,务必调用 wp_reset_postdata()
  2. 使用 pre_get_posts 修改主查询:不要轻易使用 query_posts()
  3. 利用缓存:如果你的查询结果不经常变化,可以考虑使用 WordPress 对象缓存或插件(如 WP Rocket)来缓存查询结果,极大提升网站速度。
  4. 避免 N+1 查询问题:在循环中多次调用函数(如 get_the_category())可能会导致数据库查询次数过多,可以在循环前一次性获取所有需要的数据,或者在循环中使用 setup_postdata() 来优化。

希望这份详细的指南能帮助你完全掌握 WordPress 的查询模板!