I have posts with two categories, for example, 1st post is in category "product" and "shoes", 2nd is in category "product" and "shirts", 3rd is in category "product" and "sport clothes"... So, posts have one mutual category ("product" in this example), and one more specific category.

I tried to get previous/next post with:

$next_post = get_next_post( true );
$previous_post = get_previous_post( true );

But then, for example on 2nd post I have 1st and 3rd post as previous/next posts, because they have one mutual category "product". I would like that on post about shirts I have other posts only which are in shirts category. I tried to exclude category "product" by it's ID like this:

$next_post = get_next_post( true, '5', category  ); // 5 is ID of "product" category
$previous_post = get_previous_post( true, '5', category ); // 5 is ID of "product" category

But then I have no previous/next posts, because posts in "shirts" category are also in "product" category and function above says to exclude posts from that category.

Is there any way to do opposite, just to include posts which have one specific category?

  • Your nick mean understanding what information architecture is.
    – Max Yudin
    May 8, 2019 at 13:26

1 Answer 1


When in_same_term parameter in get_next_post() / get_previous_post() function is set to TRUE, a post is selected from any category assigned to the current post.

As you wrote, you can not use the exclude parameter in this case.

Using the get_{$adjacent}_post_where filter, you can skip product in the category list, which you are looking for posts. First you get IDs of the categories assigned to current post, next you delete unwanted IDs from the list, and finally you replace the relevant part of the "where" statement in the query string.

add_filter( 'get_next_post_where', 'se337397_adjacent_from_category', 15, 5 );
add_filter( 'get_previous_post_where', 'se337397_adjacent_from_category', 15, 5 );

function se337397_adjacent_from_category( $where, $in_same_term, $excluded_terms, $taxonomy, $post )
    if ( $in_same_term == FALSE || 'post' != $post->post_type )
        return $where;

    // category IDs to ignore when choosing an adjacent post
    $to_ignore = [ 5 ]; 
    // or get ID by slug (term='product', taxonomy='category'):
    //    $term = get_term_by('slug', '{your_term_slug}', '{your_taxonomy}');
    //    if ( $term === false )
    //        return $where;
    //    $to_ignore = [ $term->term_id ];

    // get terms assigned to current post
    $term_array = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'ids' ) );
    // Remove any exclusions and ignored from the term array to include.
    $term_array = array_diff( $term_array, (array)$excluded_terms, $to_ignore );

    $term_array = array_map( 'intval', $term_array );
    if ( ! $term_array || is_wp_error( $term_array ) )
        $term_array = [ 0 ];
    // replace a part of the query string that limits results to given terms (categories)
    $sql__in_terms = ' AND tt.term_id IN (' . implode( ',', $term_array ) . ')';
    $in_begin = strpos( $where, 'AND tt.term_id IN' );
    $in_end = strpos( $where, ')', $in_begin );

    $new_where = substr( $where, 0, $in_begin );
    $new_where .= $sql__in_terms;
    $new_where .= substr( $where, $in_end + 1 );

    return $new_where;

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.