下面我将从基础到高级,全面地为你解析 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();
?>
关键步骤解析
- 定义参数 (
$args): 这是你告诉 WordPress “我想要什么内容” 的地方,通过一个关联数组来设置各种查询条件。 - 创建实例 (
new WP_Query): 你将参数传递给WP_Query类,它会根据这些参数去数据库查询,并将结果存储在$the_query对象中。 have_posts(): 这个方法检查查询结果中是否还有文章可以显示,类似于while循环的判断条件。the_post(): 这个方法会设置当前循环的文章数据,并让模板标签(如the_title(),the_content())能够正确显示当前文章的内容。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 的文章

$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:查询同时属于 “新闻” 和 “科技” 这两个分类的文章

$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' );
工作原理:
pre_get_posts钩子在查询执行之前触发。- 我们通过
$query->is_home()判断当前是否是首页。 $query->is_main_query()确保我们只修改 WordPress 的主要查询,而不是我们自定义的WP_Query循环。$query->set( 'cat', '-1' )直接修改即将执行的查询参数,将其cat值设为 -1(排除 ID 为 1 的分类)。- 这样,当 WordPress 执行首页的主查询时,就会自动排除该分类下的文章。
最佳实践与性能优化
- 总是重置数据:在使用完
WP_Query后,务必调用wp_reset_postdata()。 - 使用
pre_get_posts修改主查询:不要轻易使用query_posts()。 - 利用缓存:如果你的查询结果不经常变化,可以考虑使用 WordPress 对象缓存或插件(如 WP Rocket)来缓存查询结果,极大提升网站速度。
- 避免
N+1查询问题:在循环中多次调用函数(如get_the_category())可能会导致数据库查询次数过多,可以在循环前一次性获取所有需要的数据,或者在循环中使用setup_postdata()来优化。
希望这份详细的指南能帮助你完全掌握 WordPress 的查询模板!
