pre_get_posts:想改主查询,该走这个门

作者: admin 分类: wordpress主题制作教程 发布时间: 2026-11-06 18:30

一个常见需求

“我想让首页每页显示 20 篇文章,而不是后台设置的 10 篇。”

很多人第一反应是改 index.php,或者在模板里 query_posts。但这两条路都不对:

  • 改模板 → 只改了显示,分页还是按 10 篇算,会错乱;
  • 用 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 );
    }
} );

三个判断,一个都不能少:

  1. is_admin():后台不要改,否则后台文章列表也会变成 20 篇;
  2. $query->is_main_query():只改主查询,别把侧栏、相关文章的查询也改了;
  3. 条件判断(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

对比一下:

query_posts pre_get_posts
改的是 已经查完的结果(替换) 查询之前的参数
分页 错乱 正确
性能 多查一次 不多查
位置 模板里 functions.php

关键差别:pre_get_posts 改的是“订单”,分页、计数全都跟着对;query_posts 是“菜都上完了再换一桌”,分页当然对不上。

一个坑:别在 pre_get_posts 里 new WP_Query

有人会在 pre_get_posts 里再 new 一个查询,这是大忌——会触发无限递归(查文章 → 触发钩子 → 又查文章 → …)。

要改参数,就用 $query->set(),别新建查询。

小结

一句话记住:想改主查询,用 pre_get_posts + 三个判断(is_admin / is_main_query / 条件),别用 query_posts。

下一篇讲 WP_Query 和分页怎么配合——自己查的文章,分页要自己算。

本系列导航

相关文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Powered by 草根站长笔记 © 2015-2026 草根站长笔记 Inc.版权所有,禁止转载