問題描述
我有一系列由 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 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。