
本文详解 Timber 框架中 WordPress 默认主查询分页失效的根本原因及修复方法,涵盖 pre_get_posts 钩子正确配置、Timber\PostQuery 替代手动查询、Twig 分页模板调用规范,并解释 dump() 不生效的底层机制。
本文详解 timber 框架中 wordpress 默认主查询分页失效的根本原因及修复方法,涵盖 `pre_get_posts` 钩子正确配置、`timber\postquery` 替代手动查询、twig 分页模板调用规范,并解释 `dump()` 不生效的底层机制。
在使用 Timber 构建 WordPress 主题时,直接通过 Timber::get_posts() 手动构造查询会导致分页(Pagination)失效——这是初学者常见误区。根本原因在于:WordPress 的原生分页逻辑(如 paged 参数解析、总页数计算、WP_Query 全局状态同步)仅对主查询($wp_query)生效;而 Timber::get_posts() 返回的是独立的 WP_Query 实例,其分页数据无法被 Timber 的 pagination() 方法自动识别。
✅ 正确做法:接管主查询,而非新建查询
应放弃在 home.php 中手动调用 Timber::get_posts(),转而通过 pre_get_posts 钩子修改 WordPress 主查询行为。此方式确保分页参数(如 /page/2/)被正确解析,且 Timber\PostQuery() 能无缝继承主查询的分页上下文。
步骤 1:在 functions.php 中注册主查询过滤器
// functions.php
function modify_blog_posts_query($query) {
// 仅作用于首页主查询(避免影响后台、搜索等其他查询)
if ($query->is_home() && $query->is_main_query()) {
$query->set('posts_per_page', 2); // 每页显示 2 篇文章
$query->set('offset', 1); // 跳过第 1 篇(注意:offset 与分页兼容性需谨慎)
// ⚠️ 注意:若需 offset,请确认是否真有必要——它会破坏标准分页(因 offset 不参与 total_posts 计算)
// 更推荐用 'post__not_in' 或自定义 SQL,或直接移除 offset
}
}
add_action('pre_get_posts', 'modify_blog_posts_query');? 关键说明:$query->is_home() 判断的是 WordPress 的“博客首页”(即 posts_page),非静态首页。若你使用的是静态首页(is_front_page()),请相应调整条件。
步骤 2:重构 home.php,使用 Timber\PostQuery
<?php
use Timber\Post;
use Timber\Timber;
use Timber\PostQuery; // ✅ 必须引入
$context = Timber::context();
$context['post'] = new Post(); // 当前页面 Post 对象(如首页 Page)
// ✅ 使用 PostQuery 接管主查询(自动继承 $wp_query 的分页状态)
$context['posts'] = new PostQuery();
// 获取最新一篇(独立查询,不影响主查询分页)
$args_latest = [
'posts_per_page' => 1,
'post_status' => 'publish',
];
$context['latest'] = Timber::get_posts($args_latest);
Timber::render('page-home.twig', $context);步骤 3:Twig 模板中正确调用分页
page-home.twig 中:
{# 渲染文章列表 #}
{% for post in posts %}
<article>
<h2>{{ post.title }}</h2>
<p>{{ post.excerpt }}</p>
</article>
{% endfor %}
{# ✅ 正确:传递 PostQuery 实例,自动获取分页元数据 #}
{% include 'partial/pagination.twig' with {
pagination: posts.pagination({
show_all: false,
mid_size: 3,
end_size: 2
})
} %}
{# ✅ dump 现在可正常工作 #}
{{ dump(posts) }}? dump(posts) 原先失效,是因为 Timber::get_posts() 返回的是普通数组(array)或 PostCollection,而 dump() 在 Twig 中对非对象/非可遍历结构支持有限;Timber\PostQuery 是一个具备完整 __debugInfo() 和 toArray() 方法的类实例,因此 dump() 可清晰输出其内部查询状态、分页信息(如 current, total, base_url 等)。
⚠️ 重要注意事项
-
offset 与分页冲突:offset 参数会破坏 WP_Query 的 found_posts 和 max_num_pages 计算,导致分页链接错误或 404。若需“跳过最新一篇”,建议改用:
// 在 pre_get_posts 中 $query->set('post__not_in', [$latest_id]); // 需提前获取 latest_id - 分页 URL 规范:确保 WordPress 设置 → 阅读 → “博客页面” 已正确指定,且固定链接已保存(刷新重写规则)。
- post_staus 拼写错误:原代码中 'post_staus' => 'published' 应为 'post_status' => 'publish'(publish 是标准值,published 非有效状态)。
✅ 总结
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 分页不显示/链接错误 | 手动 get_posts() 绕过主查询,丢失分页上下文 | 使用 pre_get_posts 修改主查询 + Timber\PostQuery |
| {{ dump(posts) }} 无输出 | get_posts() 返回数组,非可调试对象 | 改用 PostQuery 实例,支持完整调试信息 |
| offset 导致分页异常 | offset 干扰 found_posts 计算 | 避免在分页查询中使用 offset,改用 post__not_in 或自定义逻辑 |
遵循以上模式,即可让 Timber 分页与 WordPress 原生机制完全协同,稳定、高效、可维护。

















