Get Previous & Next posts by Post ID

How can I go about getting the previous and next posts from outside the loop? Everything I try to do aside from the custom SELECT query (using get_posts or WP_Query) breaks stuff further down the page.

I currently have a recursive function which will hopefully find the first “previous” post which satisfies a certain condition. I grab the first value to test from get_previous_post() but don’t know how to get the previous_previous_post().

add_action( 'wp_ajax_nopriv_myajax-submit', 'ajax_project_load' );
add_action( 'wp_ajax_myajax-submit', 'ajax_project_load' );

function ajax_project_load() {
    $the_slug = $_POST['slug'];
    $args=array(
      'name' => $the_slug,
      'post_type' => 'projects',
      'post_status' => 'publish',
      'showposts' => 1,
      'ignore_sticky_posts' => 1
    );
    $my_posts = get_posts($args);
    if( $my_posts ) :

        global $post;
        $post = $my_posts[0]; 
        $postCapabilityFilter = $_POST['capFilter']=='undefined' ? $_POST['capFilter'] : substr($_POST['capFilter'], 1);

        $response = json_encode( "Success" );
        header( "Content-Type: application/json" );     


$next_post = get_previous_post();
function filtered_next_post($next_post){
    if($next_post){
        $next_slug = $next_post->post_name;
        $next_ID = $next_post->ID;
        global $wpdb;
        global $postCapabilityFilter;
        $querystr = "
        SELECT $wpdb->postmeta.*
        FROM $wpdb->posts, $wpdb->postmeta
        WHERE $wpdb->posts.post_type = 'projects' 
        AND $wpdb->posts.post_status = 'publish' 
        AND $wpdb->posts.ID = $next_ID
        AND $wpdb->posts.ID = $wpdb->postmeta.post_id
        AND $wpdb->postmeta.meta_key = '_slideshow_content'
        ORDER BY $wpdb->posts.post_name DESC
        ";
        $nextProjQuery = $wpdb->get_results($querystr, OBJECT);
        foreach($nextProjQuery as $nextProj):
            $nextProjMetaArr = unserialize($nextProj->meta_value);
            foreach ($nextProjMetaArr['slides'] as $npSlideArr){
                echo 'and..';
                if ( !in_array( $postCapabilityFilter, $npSlideArr['slideCap'] ) ){
                    echo 'not in it..';
                    //$next_post = get_previous_previous_post();
                    //filtered_next_post($next_post);
                }
            }
        endforeach;                        
        return $next_slug;
    }
}
$next_slug = filtered_next_post($next_post);

Related posts

Leave a Reply

3 comments

  1. Take a look at get_previous_post() and get_next_post() and you’ll see they both use the get_adjacent_post() to find the previous or next post.

    Let’s say you want to fetch the ID of the immediately previous post based on the current post’s ID. This is what you’d do:

    function get_previous_post_id( $post_id ) {
        // Get a global post reference since get_adjacent_post() references it
        global $post;
    
        // Store the existing post object for later so we don't lose it
        $oldGlobal = $post;
    
        // Get the post object for the specified post and place it in the global variable
        $post = get_post( $post_id );
    
        // Get the post object for the previous post
        $previous_post = get_previous_post();
    
        // Reset our global object
        $post = $oldGlobal;
    
        if ( '' == $previous_post ) {
            return 0;
        }
    
        return $previous_post->ID;
    }
    

    You can do a similar thing to fetch the next post’s ID … and you can do this recursively if you need to get the previous previous post:

    $two_posts_ago = get_previous_post_id( get_previous_post_id( $post->ID ) );
    

    TL;DR

    Essentially, both get_previous_post() and get_next_post() reference a global $post object to do their selection. You need to set this object up before calling either function or they won’t know what post to use as a reference for next/previous.

    The wrapper function above just sets up the global $post for you based on a passed-in ID. You could have it return the entire object for the previous post rather than the ID, it’s entirely up to you.

  2. Here, you can get adjacent post for specific post type with custom sql query & with filter
    get_{$adjacent}_post_where where default adjacent is previous. Also result depends on $current_post_date & comparison operator $op.

    function bm_get_adjacent_post( $post_id, $author_id, $previous = 1 ) {
    global $wpdb;
    
    if ( ( ! $post = get_post( $post_id ) )  )
        return null;
    
    $current_post_date = $post->post_date;
    
    $adjacent = $previous ? 'previous' : 'next';
    $op = $previous ? '<' : '>';
    $order = $previous ? 'DESC' : 'ASC';
    
    $where = apply_filters( "get_{$adjacent}_post_where", $wpdb->prepare( "WHERE  p.post_date $op %s AND p.post_type = %s AND p.post_status = 'publish' AND p.post_author = %d", $current_post_date, 'projects' , $author_id ), '', '' );
    $sort  = apply_filters( "get_{$adjacent}_post_sort", "ORDER BY p.post_date $order LIMIT 1" );
    
    $query = "SELECT p.ID FROM $wpdb->posts AS p $where $sort";
    //echo $query;
    $result = $wpdb->get_var( $query );
    if ( null === $result )
        $result = '';
    if ( $result )
        $result = get_post( $result );
    
    return $result;
    }
    
  3. I love this answer found at: https://stackoverflow.com/a/33688032/2062851

    function get_previous_post_id( $post_id ) {
        // Get a global post reference since get_adjacent_post() references it
        global $post;
        // Store the existing post object for later so we don't lose it
        $oldGlobal = $post;
        // Get the post object for the specified post and place it in the global variable
        $post = get_post( $post_id );
        // Get the post object for the previous post
        $previous_post = get_previous_post();
        // Reset our global object
        $post = $oldGlobal;
        if ( '' == $previous_post ) 
            return 0;
        return $previous_post->ID; 
    } 
    
    function get_next_post_id( $post_id ) {
        // Get a global post reference since get_adjacent_post() references it
        global $post;
        // Store the existing post object for later so we don't lose it
        $oldGlobal = $post;
        // Get the post object for the specified post and place it in the global variable
        $post = get_post( $post_id );
        // Get the post object for the next post
        $next_post = get_next_post();
        // Reset our global object
        $post = $oldGlobal;
        if ( '' == $next_post ) 
            return 0;
        return $next_post->ID; 
    } 
    

    then all you would do is call the function like:

    echo get_previous_post_id( $current_id );
    echo get_next_post_id( $current_id );