“我想让首页每页显示 20 篇文章,而不是后台设置的 10 篇。”
很多人第一反应是改 index.php,或者在模板里 query_posts。但这两条路都不对:
正确的入口是 pre_get_posts 钩子。
pre_get_posts 是 WordPress 在“执行查询之前”抛出的一个钩子。你在这里改查询参数,WordPress 就按你改的去查。
打个比方:主查询是“服务员去厨房下单”。pre_get_posts 就是“下单之前,你把菜单改一下”。改的是订单本身,不是端上来的菜。
改订单,比改菜(模板)管用——因为分页、计数、判断,全都基于订单。
add_action( 'pre_get_posts', function ( $query ) {
// 后台不干预
if ( is_admin() ) {
return;
}
// 只改主查询,不碰自定义查询
if ( ! $query->is_main_query() ) {
return;
}
// 只改首页
if ( $query->is_home() ) {
$query->set( 'posts_per_page', 20 );
}
} );
三个判断,一个都不能少:
is_admin():后台不要改,否则后台文章列表也会变成 20 篇;$query->is_main_query():只改主查询,别把侧栏、相关文章的查询也改了;is_home() 等):只在你想要的那个页面生效。少任何一个,都会出“莫名其妙全站都变了”的问题。
$query->set( 'orderby', 'modified' );
$query->set( 'order', 'DESC' );
if ( $query->is_search() ) {
$query->set( 'post_type', 'post' );
}
if ( $query->is_category() ) {
$query->set( 'cat', '-5' ); // 排除 ID 为 5 的分类
}
对比一下:
| query_posts | pre_get_posts | |
|---|---|---|
| 改的是 | 已经查完的结果(替换) | 查询之前的参数 |
| 分页 | 错乱 | 正确 |
| 性能 | 多查一次 | 不多查 |
| 位置 | 模板里 | functions.php |
关键差别:pre_get_posts 改的是“订单”,分页、计数全都跟着对;query_posts 是“菜都上完了再换一桌”,分页当然对不上。
有人会在 pre_get_posts 里再 new 一个查询,这是大忌——会触发无限递归(查文章 → 触发钩子 → 又查文章 → …)。
要改参数,就用 $query->set(),别新建查询。
一句话记住:想改主查询,用 pre_get_posts + 三个判断(is_admin / is_main_query / 条件),别用 query_posts。
下一篇讲 WP_Query 和分页怎么配合——自己查的文章,分页要自己算。