I'm working on a Custom Post Type sorted on a Custom Field. No problem when I list out the posts. But when I go to the single post page for one of these, I want the Prev and Next navigation links to take us to the prev/next posts in the sort order dictated by the Custom Field. By default, WP orders them by post date.

Code for sorting list:

    // shortcodes
    // lor_list of letters: Lists all letters of reference in a table format
    add_shortcode('lor_list', 'aaaConsultant_shortcode_lor_list');

    function aaaConsultant_shortcode_lor_list() {
        global $wp_query;

        $oWP = new wp_query(array(
            'post_type' => 'letters_of_ref'
            , 'orderby' => 'meta_value'
            , 'meta_key' => 'aaaConsultant_dateofletter'

        $out = '<div id="lor_list_container">' . "\n";
        if (!$oWP->found_posts) {
            $out .= '<p>d\'Oh! We don\'t have any Letters of Reference yet.</p>' . "\n";
        } else {
            while ($oWP->have_posts()) {
                $out .= '<a href="' . get_permalink() . '">' . get_the_title( $oWP->post->ID ) . '</a>' . "<br>\n";
        $out .= '</div> <!-- END #lor_list_container -->' . "\n";

        return $out;

How do I do that?

Thanks for your help.

  • Please post your code both for sorting and for generating the navigation links.
    – s_ha_dum
    Apr 21, 2013 at 17:16
  • @s_ha_dum I've added the list sort code. The prev/next code on the template, at this point, isn't worth posting: just a call to previous_posts_link(). Apr 21, 2013 at 17:41
  • Found this Q/A with some interesting info I haven't quite figured out yet because it's not a full function: Question and Answer Apr 21, 2013 at 17:48

1 Answer 1


For previous and next post links to work, you need to hook on to the get_*_post_* filters and modify the query to actually sort the posts using your custom field. I hope the code below will work for you.

For Previous post link

add_filter('get_previous_post_join', 'wpse96670_get_previous_post_join_custom_sort');
add_filter('get_previous_post_where', 'wpse96670_get_previous_post_where_custom_sort');
add_filter('get_previous_post_sort', 'wpse96670_get_previous_post_sort_custom_sort');
function wpse96670_get_previous_post_join_custom_sort($join) {
    global $wpdb;
    return "INNER JOIN {$wpdb->prefix}postmeta ON (p.ID = {$wpdb->prefix}postmeta.post_id)";
function wpse96670_get_previous_post_where_custom_sort($where) {
    global $wpdb, $post;
    $meta_value = get_post_meta($post->ID, 'aaaConsultant_dateofletter', true);
    return "WHERE 1=1  AND p.post_type = 'letters_of_ref' AND p.post_status = 'publish' AND {$wpdb->prefix}postmeta.meta_key = 'aaaConsultant_dateofletter' AND {$wpdb->prefix}postmeta.meta_value < '{$meta_value}'";
function wpse96670_get_previous_post_sort_custom_sort($sort) {
    global $wpdb;
    return "ORDER BY {$wpdb->prefix}postmeta.meta_value DESC LIMIT 1";

For next post link

add_filter('get_next_post_join', 'wpse96670_get_next_post_join_custom_sort');
add_filter('get_next_post_where', 'wpse96670_get_next_post_where_custom_sort');
add_filter('get_next_post_sort', 'wpse96670_get_next_post_sort_custom_sort');
function wpse96670_get_next_post_join_custom_sort($join) {
    global $wpdb;
    return "INNER JOIN {$wpdb->prefix}postmeta ON (p.ID = {$wpdb->prefix}postmeta.post_id)";
function wpse96670_get_next_post_where_custom_sort($where) {
    global $wpdb, $post;
    $meta_value = get_post_meta($post->ID, 'aaaConsultant_dateofletter', true);
    return "WHERE 1=1  AND p.post_type = 'letters_of_ref' AND p.post_status = 'publish' AND {$wpdb->prefix}postmeta.meta_key = 'aaaConsultant_dateofletter' AND {$wpdb->prefix}postmeta.meta_value > '{$meta_value}'";
function wpse96670_get_next_post_sort_custom_sort($sort) {
    global $wpdb;
    return "ORDER BY {$wpdb->prefix}postmeta.meta_value ASC LIMIT 1";

Then you need some code in the template:

        $oNext = get_adjacent_post(false, '', true);
        $oPrev = get_adjacent_post(false, '', false);

        if ($oPrev || $oNext) {
            echo '<div id="lor_nav">' . "\n";
        if ($oPrev) {
            echo '<div class="prevlink"><a href="' . get_permalink($oPrev->ID) . '"> &laquo; ' . $oPrev->post_title . '</a></div>' . "\n";
        if ($oNext) {
            echo '<div class="nextlink"><a href="' . get_permalink($oNext->ID) . '">' . $oNext->post_title . ' &raquo;</a></div>' . "\n";
        if ($oPrev || $oNext) {
            echo '</div><div class="clear"></div>' . "\n";

Let me know if you need any clarification.

  • Thank you. This makes it a lot clearer to me. It looks like a lot of moving parts. Perhaps it would be easier to make call directly myself, without the intervening filters. (Whoa. Just realized you coded this for my plugin. Mighty neighbourly of you.) I'm going to try this right away. Apr 22, 2013 at 2:30
  • Thanks @HameedullahKhan. It needed a couple of tweaks (quotes around the date comparison, which I've added here), but it worked like a charm. Also, needed to show the template part, so I put that in too. Feel free to edit as needed. Thanks again. This was weighing heavily on me. Apr 22, 2013 at 3:17
  • Glad you could use it for your work. :) Apr 22, 2013 at 8:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.