EP035. “用 pre_get_posts 调整默认查询(而不是重写归档页)”
🔒 登录后可标记已读上一讲把首页的 Upcoming Events 按 event_date 排序并过滤掉过去的活动,但「View All Events」归档页(archive-event.php)还是照 WordPress 默认查询(按发布日期排序,不过滤过去活动)。第一反应可能是在 archive-event.php 里也写一个全新的 WP_Query,但这一讲的重点是:归档页本来就有 WordPress 自动生成的默认查询,没必要整个推翻重写,直接重写会让分页(pagination)变得麻烦。更好的做法是用 pre_get_posts 这个 hook,在 WordPress 把查询送去数据库「之前」,拿到这个默认查询对象,直接在原有查询上做几个参数微调。首页的 Upcoming Events 因为本来就不是默认查询该管的范围(默认查询只会查首页这一个页面),所以那边继续保留自定义 WP_Query 是对的;但归档页这种「跟当前 URL 强绑定」的场景,调整默认查询才是正确工具。
涉及文件
wp-content/themes/fictional-university-theme/functions.php(修改:新增university_adjust_queries()函数,挂到pre_get_posts)wp-content/themes/fictional-university-theme/archive-event.php(修改:日期圈从写死的Mar/25换成动态取值,跟首页写法一致)wp-content/themes/fictional-university-theme/front-page.php(修改:posts_per_page从上一讲实验用的-1改回2;排序/过滤参数不变)
代码实现
1. functions.php —— 新增 pre_get_posts 钩子函数
// wp-content/themes/fictional-university-theme/functions.php
// 加在文件最后:
function university_adjust_queries($query) {
if (!is_admin() AND is_post_type_archive('event') AND $query->is_main_query()) {
$today = date('Ymd');
$query->set('meta_key', 'event_date');
$query->set('orderby', 'meta_value_num');
$query->set('order', 'ASC');
$query->set('meta_query', array(
array(
'key' => 'event_date',
'compare' => '>=',
'value' => $today,
'type' => 'numeric'
)
));
}
}
add_action('pre_get_posts', 'university_adjust_queries');
要点:
pre_get_posts这个 hook 会在 WordPress 把查询真正送去数据库之前触发,并把当前的查询对象($query)传给我们的函数,让我们有机会在最后一刻改它的参数。- 这个函数一开始(教学演示阶段)如果什么条件判断都不加,会把
posts_per_page这类调整应用到网站所有查询上——不只是前台 events 归档页,连博客归档、甚至后台文章列表页都会被强制改成一页一条,这是这一讲特地做实验暴露出的问题。 - 所以最终版加了三层条件把范围收紧:
!is_admin()—— 只在前台生效,不影响后台管理画面;is_post_type_archive('event')—— 只在 event 的归档页生效,不影响博客归档等其他页面;$query->is_main_query()—— 只调整「跟当前 URL 绑定的默认主查询」,不会误伤页面里其他手写的自定义WP_Query。
- 具体调整的四个参数(
meta_key/orderby/order/meta_query)跟 EP034 首页那套逻辑完全一样,直接照抄过来改成用$query->set($key, $value)的写法逐个设置。
2. archive-event.php —— 日期圈换成动态数据
// wp-content/themes/fictional-university-theme/archive-event.php
// while 循环里的日期圈,从写死的 Mar / 25 换成:
<a class="event-summary__date t-center" href="#">
<span class="event-summary__month"><?php
$eventDate = new DateTime(get_field('event_date'));
echo $eventDate->format('M')
?></span>
<span class="event-summary__day"><?php echo $eventDate->format('d') ?></span>
</a>
这段代码直接从首页复制过来,跟 EP032/EP034 的写法一致。注意这个循环用的仍是裸的 have_posts()/the_post()(因为走的是默认查询,只是被 pre_get_posts 悄悄调整过参数,模板本身不需要知道这件事)。
3. front-page.php —— posts_per_page 改回 2
// wp-content/themes/fictional-university-theme/front-page.php
// Upcoming Events 的 WP_Query 参数里:
'posts_per_page' => 2, // 从上一讲实验用的 -1 改回 2,恢复首页只显示最近两场活动
首页这个查询的 meta_key/orderby/order/meta_query 部分维持 EP034 的写法不变,只有 posts_per_page 改回 2。
Hook / Function 速查
| 名称 | 类型 | 用途 |
|---|---|---|
pre_get_posts | WP hook | 在 WordPress 执行查询前触发,可以拿到查询对象并修改其参数 |
$query->set($key, $value) | WP_Query 方法 | 在 pre_get_posts 里用来设置/覆盖某个查询参数 |
is_admin() | WP 内建 function | 判断当前是否在后台管理画面 |
is_post_type_archive($post_type) | WP 内建 function | 判断当前是否在指定文章类型的归档页 |
$query->is_main_query() | WP_Query 方法 | 判断传入的查询是否是跟当前 URL 绑定的主查询(而非页面里额外手写的自定义查询) |
常见坑
pre_get_posts挂上去后如果不加任何条件判断,会把参数调整应用到网站所有查询:不仅前台博客归档会被误改,连后台的文章列表、事件列表也会被强制改成一页一条——这是这一讲特意演示的坑,用来说明为什么必须加条件收紧范围。- 只用
is_admin()判断不够精确,还需要加is_post_type_archive('event'),否则前台博客归档也会被一起改掉。 - 再加上
$query->is_main_query()作为第三层保险,避免以后页面上出现别的自定义WP_Query时被误伤。
延伸 / 后续讲座会用到
下一讲 EP036 会做一个新的「Past Events」页面模板,需要用到自定义 WP_Query(因为这不是默认 URL 查询能覆盖的场景),并且要额外处理自定义查询下分页失效的问题。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 7, EP035