Make get_adjacent_post() work across custom post types

Using get_adjacent_post, previous_post_link, and next_post_link only seems to recognize items which are of the same post type. Since I have 2 custom post types is there a way to link between all previous and next post types?

Related posts

Leave a Reply

2 comments

  1. It appears this question has been asked all over the interweb with no definite answer. So I created my own function from the original get_adjacent_post and customized it for anyone else who needs it.

    The Function

    Drop this in your functions.php

    /*
     * Replacement for get_adjacent_post()
     *
     * This supports only the custom post types you identify and does not
     * look at categories anymore. This allows you to go from one custom post type
     * to another which was not possible with the default get_adjacent_post().
     * Orig: wp-includes/link-template.php 
     * 
     * @param string $direction: Can be either 'prev' or 'next'
     * @param multi $post_types: Can be a string or an array of strings
     */
    function mod_get_adjacent_post($direction = 'prev', $post_types = 'post') {
        global $post, $wpdb;
    
        if(empty($post)) return NULL;
        if(!$post_types) return NULL;
    
        if(is_array($post_types)){
            $txt = '';
            for($i = 0; $i <= count($post_types) - 1; $i++){
                $txt .= "'".$post_types[$i]."'";
                if($i != count($post_types) - 1) $txt .= ', ';
            }
            $post_types = $txt;
        }
    
        $current_post_date = $post->post_date;
    
        $join = '';
        $in_same_cat = FALSE;
        $excluded_categories = '';
        $adjacent = $direction == 'prev' ? 'previous' : 'next';
        $op = $direction == 'prev' ? '<' : '>';
        $order = $direction == 'prev' ? 'DESC' : 'ASC';
    
        $join  = apply_filters( "get_{$adjacent}_post_join", $join, $in_same_cat, $excluded_categories );
        $where = apply_filters( "get_{$adjacent}_post_where", $wpdb->prepare("WHERE p.post_date $op %s AND p.post_type IN({$post_types}) AND p.post_status = 'publish'", $current_post_date), $in_same_cat, $excluded_categories );
        $sort  = apply_filters( "get_{$adjacent}_post_sort", "ORDER BY p.post_date $order LIMIT 1" );
    
        $query = "SELECT p.* FROM $wpdb->posts AS p $join $where $sort";
        $query_key = 'adjacent_post_' . md5($query);
        $result = wp_cache_get($query_key, 'counts');
        if ( false !== $result )
            return $result;
    
        $result = $wpdb->get_row("SELECT p.* FROM $wpdb->posts AS p $join $where $sort");
        if ( null === $result )
            $result = '';
    
        wp_cache_set($query_key, $result, 'counts');
        return $result;
    }
    

    Usage

    Basic use

    // Custom post types can be array() or string
    $post1 = mod_get_adjacent_post('prev', array('post', 'custom1', 'custom2'));
    $post2 = mod_get_adjacent_post('next', 'custom2');
    

    For creating prev/next links

    <?php
    $prev = mod_get_adjacent_post('prev', array('post', 'custom1', 'custom2'));
    $next = mod_get_adjacent_post('next', array('post', 'custom1', 'custom2'));
    ?>
    
    <?php if($prev) : ?>
        <a href="<?php echo get_permalink($prev->ID)?>">&laquo; Go back in time</a>
    <?php endif; ?>
    
    <?php if($next) : ?>
        <a href="<?php echo get_permalink($next->ID)?>">Next: <?php echo $next->post_title; ?> &raquo;</a>
    <?php endif; ?>
    

    You can still modify the code if you still want to include the variables $in_same_cat and $excluded_categories but if you do then I suggest you use get_adjacent_post instead since that’s what it’s for.

  2. The previous answer it’s not longer working. Check this one out

    I came up with a new one, quite more simple:

    • Paste this into your functions.php
    function custom_posttype_get_adjacent_ID($direction = 'next', $type = 'post', $current) {
    
        // Get all posts with this custom post type
        $posts = get_posts('posts_per_page=-1&order=DESC&post_type='.$type);
    
        $postsLength = sizeof($posts)-1;
        $currentIndex = 0;
        $index = 0;
        $result = 0;
    
        // Iterate all posts in order to find the current one
        foreach($posts as $p){
            if($p->ID == $current) $currentIndex = $index;
            $index++;
        }
        if($direction == 'prev') {
            // If it's 'prev' return the previous one unless it's the first one, in this case return the last. 
            $result = !$currentIndex ? $posts[$postsLength]->ID : $posts[$currentIndex - 1]->ID;
        } else {
            // If it's 'next' return the next one unless it's the last one, in this case return the first. 
            $result = $currentIndex == $postsLength ? $posts[0]->ID : $posts[$currentIndex + 1]->ID;
        }
        return $result;
    }
    

    Now wherever you need the next-prev post ID just use the function like this:

    custom_posttype_get_adjacent_ID('prev', 'project', get_the_ID());
    

    Comments:

    • Feel free to replace the get_the_ID()for your current post ID if you feel like it.
    • First parameters expects to be ‘next’ or ‘prev’, it falls back to ‘next’.
    • Second parameter needs to be the custom post type name. You can find it in your register_post_type()function. It falls back to ‘post’.
    • If the last parameter it’s empty it won’t work.

    Examples:

    If you want the next or prev post permalink you can use it like this:

    <?php echo get_permalink(custom_posttype_get_adjacent_ID('prev', 'project', get_the_ID())); ?>
    

    So with the tag it would look something like this:

    <a href="<?php echo get_permalink(custom_posttype_get_adjacent_ID('prev', 'project', get_the_ID())); ?>">Previous Project</a>
    

    Could not test it a lot so if it’s not working in some cases let me know and I’ll try to fix it / improve it.