Understanding the internals
The "sort" order of adjacent (next/prev) posts is not really a sort "order". It's a separate query on each request/page, but it sorts the query by the post_date
- or the post parent if you have a hierarchical post as currently displayed object.
When you take a look at the internals of next_post_link()
, then you see that it's basically an API wrapper for adjacent_post_link()
. The later function calls get_adjacent_post()
internally with the $previous
argument/flag set to bool(true|false)
to grab the next or previous post link.
What to filter?
After digging deeper into it, you'll see that get_adjacent_post()
Source link has some nice filters for its output (a.k.a. query result): (Filter Name/Arguments)
"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"`
So you can do alot with it. That starts with filtering the WHERE
clause, as well as the JOIN
ed table and the ORDER BY
statement.
The result gets cached in memory for the current request, so it doesn't add additional queries if you call that function multiple times on a single page.
Automatic query building
As @StephenHarris pointed out in the comments, there's a core function that might come in handy when building the SQL Query: get_meta_sql()
- Examples in Codex. Basically this function is just used to build the meta SQL statement that gets used in WP_Query
, but you can use it in this case (or others) as well. The argument that you throw into it is an array, the exact same that would add to a WP_Query
.
$meta_sql = get_meta_sql(
$meta_query,
'post',
$wpdb->posts,
'ID'
);
The return value is an array:
$sql => (array) 'join' => array(),
(array) 'where' => array()
So you can use $sql['join']
and $sql['where']
in your callback.
Dependencies to keep in mind
In your case the easiest thing would be to intercept it in a small (mu)plugin or in your themes functions.php file and alter it depending on the $adjacent = $previous ? 'previous' : 'next';
variable and the $order = $previous ? 'DESC' : 'ASC';
variable:
The actual filter names
So the filter names are:
get_previous_post_join
, get_next_post_join
get_previous_post_where
, get_next_post_where
get_previous_post_sort
, get_next_post_sort
Wrapped up as a plugin
...and the filter callback would be (for example) something like the following:
<?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' );