遇到的问题
在 WordPress WP_Query 参数中,有两个参数用到了 MySQL 的 offset 语句,一个是 paged,一个是 offset,paged 是为了实现分页,offset 是为了跳过某些文章不显示,如果这两个同时出现,会怎么样呢?答案是,offset 可以用,分页失效。
需要同时用到这两个参数的情况很少,常见的一种情况是在索引(也就是 WordPress 中的分类或标签存档页面)需要跳过前一篇或者几篇文章不显示,当然,在索引页面,分页也是需要的。
解决办法
要实现这种效果,我们就需要对 WordPres 分页功能动一下手脚了,我们主要通过以下两个 WordPress 钩子实现这个功能。
- pre_get_posts:在 WordPress 查询允许之前,调整 WordPress 查询参数,在这里,我们需要用这个钩子保证 offset 参数只应用在第一页,
- found_posts:允许我们调整 WordPress 文章查询结果总数量
第一步是使用 pre_get_posts 同时处理 offset 和分页,这个钩子把WordPress查询对象传递到自定义功能中,在自定义功能中,我们可以对查询对象进行修改。在下面的例子中,我们需要在WordPress 博客存档页面跳过前10篇文章。
add_action('pre_get_posts', 'myprefix_query_offset', 1 );
function myprefix_query_offset(&$query) {
//开始之前,确定我们在正确的位置
if ( ! $query->is_posts_page ) {
return;
}
//首先,定义需要跳过的文章数量
$offset = 10;
//下一步,获取设置中每页现实文章的数量
$ppp = get_option('posts_per_page');
//下一步,检测和处理分页
if ( $query->is_paged ) {
//手动确定查询偏移量(偏移量 + 当前页数 (减1) x 每页文章数)
$page_offset = $offset + ( ($query->query_vars['paged']-1) * $ppp );
//应用调整后的偏移量
$query->set('offset', $page_offset );
} else {
//如果是首页,只设置偏移量就可以了
$query->set('offset',$offset);
}
}
OK,两个参数可以同时使用了,但是还存在一个问题,WordPress 计算总文章数量的时候,不会把跳过的文章考虑进入,比如我们数据库里面有 25 篇文章,每页显示 10 篇,如果没有偏移,分页数为 3,这是正常的,设置了偏移量之后,正确的分页数 2,事实是,如果我们不做进一步处理,WordPress 现实出来了分页仍然是 3,这时候如果点一下第三页,不出意外肯定是404 页面,因为现实的内容总共才 15 篇,这一页根本不存在。这个问题修复起来也很简单,请看下面的代码。
add_filter('found_posts', 'myprefix_adjust_offset_pagination', 1, 2 );
function myprefix_adjust_offset_pagination($found_posts, $query) {
//定义需要跳过的文章的数量
$offset = 10;
//确保我们修改的是正确的查询对象
if ( $query->is_posts_page ) {
//用找到的文章数量减去偏移的文章数量...
return $found_posts - $offset;
}
}
应该是类似的需求很小,所以 WordPress开发团队忽略了这个 “bug”,以上是 WordPress 官方给去的解决方案,当然,解决问题的办法不止一种,如果你有更好的解决方案,欢迎在评论中提出。