问题描述
我有一系列由 meta_key 值排序的帖子。如果需要,也可以通过菜单顺序进行排列。
下一个/上一页的链接 (由 next_post_link
,previous_post_link
或 posts_nav_link
生成) 都是按时间顺序导航的虽然我明白这个默认行为,但我不明白如何改变它,我发现它在 link-template.php 中映射到 adjacent_post_link,但是它开始看起来好像是 hard-coded,推荐 re-write 从头开始替代它,还是有更好的解决方案。
最佳解决方案
了解内部
“sort” 相邻 (下一个/上一个) 帖子的顺序不是真的一个”order” 。它是每个请求/页面上的一个单独的查询,但是如果您有一个层次结构的帖子作为当前显示的对象,它会排列 post_date
的查询。
当您查看 next_post_link()
的内部组件时,您会看到它基本上是 adjacent_post_link()
的 API 封装。后来的函数在 get_adjacent_post()
内部调用 $previous
参数/标志设置为 bool(true|false)
来抓取下一个或上一个后链接。
什么要过滤?
在深入挖掘之后,您会看到 get_adjacent_post()
源链接的输出有一些不错的过滤器 (a.k.a. 查询结果):(过滤器名称/参数)
-
"get_{$adjacent}_post_join"
$join // Only if `$in_same_cat` // or: ! empty( $excluded_categories` // and then: // " INNER JOIN $wpdb->term_relationships AS tr // ON p.ID = tr.object_id // INNER JOIN $wpdb->term_taxonomy tt // ON tr.term_taxonomy_id = tt.term_taxonomy_id"; // and if $in_same_cat then it APPENDS: // " AND tt.taxonomy = 'category' // AND tt.term_id IN (" . implode(',', $cat_array) . ")"; $in_same_cat $excluded_categories
-
"get_{$adjacent}_post_where"
$wpdb->prepare( // $op = $previous ? '<' : '>'; | $current_post_date "WHERE p.post_date $op %s " // $post->post_type ."AND p.post_type = %s " // $posts_in_ex_cats_sql = " AND tt.taxonomy = 'category' // AND tt.term_id NOT IN (" . implode($excluded_categories, ',') . ')'; // OR empty string if $in_same_cat || ! empty( $excluded_categories ."AND p.post_status = 'publish' $posts_in_ex_cats_sql " ", $current_post_date, $post->post_type ) $in_same_cat $excluded_categories
-
"get_{$adjacent}_post_sort"
"ORDER BY p.post_date $order LIMIT 1"`
所以你可以做很多事情。首先过滤 WHERE
子句,以及 JOIN
表和 ORDER BY
语句。
结果将缓存在内存中用于当前请求,因此如果在单个页面上多次调用该函数,则不会添加其他查询。
自动查询建立
正如 @StephenHarris 在注释中指出的那样,构建 SQL 查询时可能会派上用场的核心功能:get_meta_sql()
– 示例 in Codex 。基本上这个函数只是用来构建 WP_Query
中使用的元 SQL 语句,但是在这种情况下也可以使用它 (或其他) 。你抛出的参数是一个数组,与 WP_Query
相同。
$meta_sql = get_meta_sql(
$meta_query,
'post',
$wpdb->posts,
'ID'
);
返回值是一个数组:
$sql => (array) 'join' => array(),
(array) 'where' => array()
所以你可以在你的回调中使用 $sql['join']
和 $sql['where']
。
依赖关系要记住
在你的情况下,最简单的事情是在一个小的 (mu) 插件或主题 functions.php 文件中截取它,并根据 $adjacent = $previous ? 'previous' : 'next';
变量和 $order = $previous ? 'DESC' : 'ASC';
变量进行更改:
实际的过滤器名称
所以过滤器名称是:
-
get_previous_post_join
,get_next_post_join
-
get_previous_post_where
,get_next_post_where
-
get_previous_post_sort
,get_next_post_sort
封装成插件
… 和过滤器回调将是 (例如) 类似于以下内容:
<?php
/** Plugin Name: (#73190) Alter adjacent post link sort order */
function wpse73190_adjacent_post_sort( $orderby )
{
return "ORDER BY p.menu_order DESC LIMIT 1";
}
add_filter( 'get_previous_post_sort', 'wpse73190_adjacent_post_sort' );
add_filter( 'get_next_post_sort', 'wpse73190_adjacent_post_sort' );
次佳解决方案
Kaiser’s answer 是非常棒和彻底的,但只要更改 ORDER BY 子句是不够的,除非您的 menu_order
符合您的时间顺序。
我不能信用这个,但是我在 this gist 中找到了以下代码:
<?php
/**
* Customize Adjacent Post Link Order
*/
function wpse73190_gist_adjacent_post_where($sql) {
if ( !is_main_query() || !is_singular() )
return $sql;
$the_post = get_post( get_the_ID() );
$patterns = array();
$patterns[] = '/post_date/';
$patterns[] = '/'[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}'/';
$replacements = array();
$replacements[] = 'menu_order';
$replacements[] = $the_post->menu_order;
return preg_replace( $patterns, $replacements, $sql );
}
add_filter( 'get_next_post_where', 'wpse73190_gist_adjacent_post_where' );
add_filter( 'get_previous_post_where', 'wpse73190_gist_adjacent_post_where' );
function wpse73190_gist_adjacent_post_sort($sql) {
if ( !is_main_query() || !is_singular() )
return $sql;
$pattern = '/post_date/';
$replacement = 'menu_order';
return preg_replace( $pattern, $replacement, $sql );
}
add_filter( 'get_next_post_sort', 'wpse73190_gist_adjacent_post_sort' );
add_filter( 'get_previous_post_sort', 'wpse73190_gist_adjacent_post_sort' );
我修改了 WP.SE 的函数名。
如果只更改了 ORDER BY 子句,则查询仍然查找大于或小于当前发布日期的帖子。如果您的帖子不按时间顺序排列,您将无法获得正确的信息。
除了修改 orderby 子句之外,这会更改 where 子句以查找 menu_order 大于或小于当前帖子的 menu_order 的帖子。
orderby 子句也不应该被硬编码以使用 DESC,因为它将需要根据您是否获得下一个或上一个链接进行切换。
第三种解决方案
function wpse73190_gist_adjacent_post_sort( $sql ) {
$pattern = '/post_date/';
$replacement = 'menu_order';
return preg_replace( $pattern, $replacement, $sql );
}
add_filter( 'get_next_post_sort', 'wpse73190_gist_adjacent_post_sort' );
add_filter( 'get_previous_post_sort', 'wpse73190_gist_adjacent_post_sort' );
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。