I am using this code, but once I click on the next post/previous post link, I am redirected to the next post/previous post of a different category.

 previous_post_link( '%link', 'Prev post in category', $in_same_term = true );
 next_post_link( '%link', 'Next post in category', $in_same_term = true );

I am trying to fix my issue using this article.

Here is the code I am using for posts and categories, and I am not using custom post types and categories:

$post_id = $post->ID;
$cat = get_the_category();
$current_cat_id = $cat[0]->cat_ID;
$args = array( 
    'category' => $current_cat_id, 
    'orderby'  => 'post_date', 
    'order'    => 'DESC' 
$posts = get_posts( $args );
foreach( $posts as $post ) {
    echo $post->post_content;
previous_post_link( '%link', 'Prev post in category', $in_same_term = true );
next_post_link( '%link', 'Next post in category', $in_same_term = true );

It's basically fetching all the posts based on the category, and now I want the next post/ previous post link to work only for this particular category.

  • Are you using the code in single.php Jun 17, 2014 at 10:54
  • For what post do you want to display the previous/next post links? For the last post in the $posts array from the code you provided, or from the main post on the current page?
    – engelen
    Jun 17, 2014 at 11:05
  • @pieter Goosen: yes i am using the code in single.php
    – user54318
    Jun 17, 2014 at 11:11
  • @engelen I am displaying all the posts with respect to the category on the current page and now i want the next and previous links to be restricted to only the current category
    – user54318
    Jun 17, 2014 at 11:27
  • All right, what kind of page is this? A single post page, a category archive, ..?
    – engelen
    Jun 17, 2014 at 11:41

5 Answers 5


Here is the code to get category based previous and next links on posts:

$post_id = $post->ID; // current post ID
$cat = get_the_category(); 
$current_cat_id = $cat[0]->cat_ID; // current category ID 

$args = array( 
    'category' => $current_cat_id,
    'orderby'  => 'post_date',
    'order'    => 'DESC'
$posts = get_posts( $args );
// get IDs of posts retrieved from get_posts
$ids = array();
foreach ( $posts as $thepost ) {
    $ids[] = $thepost->ID;
// get and echo previous and next post in the same category
$thisindex = array_search( $post_id, $ids );
$previd    = isset( $ids[ $thisindex - 1 ] ) ? $ids[ $thisindex - 1 ] : false;
$nextid    = isset( $ids[ $thisindex + 1 ] ) ? $ids[ $thisindex + 1 ] : false;

if (false !== $previd ) {
    ?><a rel="prev" href="<?php echo get_permalink($previd) ?>">Previous</a><?php
if (false !== $nextid ) {
    ?><a rel="next" href="<?php echo get_permalink($nextid) ?>">Next</a><?php
  • +1 This is exactly what I was looking for. My requirement was to order by the Order field in the Edit Page Attributes box. So I changed the $args to $args = array('category'=>$current_cat_id,'orderby'=>'menu_order','order'=> 'ASC'); and that solved my problem. Thanks a ton for sharing the solution!
    – Devner
    Oct 8, 2014 at 7:25
  • Thanks very helpful for me Jan 3, 2020 at 20:48
  • where do you put this code? Nov 7, 2020 at 15:53

The previous_post_link and next_post_link functions both have five parameters: $format: Format string for the link, used to control what comes before and after the link
$link: Link text to display
$in_same_term: Whether the next/previous post must be in the same taxonomy term as the current post
$excluded_terms: Terms from which to exclude posts $taxonomy: The taxonomy to use when $in_same_term is true As you can see, the $in_same_term parameter does exactly what you need. However, you're not using it correctly in your sample code. You're actually passing the result of assigning true to a variable $in_same_term. This won't work: passing an argument is as simple as passing a value:

previous_post_link( '%link', 'Prev post in category', true );
next_post_link( '%link', 'Next post in category', true );

Edit: (edited after OP updated his question) The problem is that previous_post_link and next_post_link use the global post object, which you're overwriting. To prevent this, use another variable name in your $posts-loop, such as $singlepost:

foreach ( $posts as $singlepost ) {
    echo $singlepost->post_content

This way, the global $post object is preserved. Alternatively, you could store the global post object in a temporary variable and reset $post again later, but that's only really necessary if you're calling setup_postdata (which you aren't).

  • Thanks for your quick response. I am still get the same result.
    – user54318
    Jun 17, 2014 at 7:50
  • You'll have to provide us with some more information than that :-). Are you using a custom post type or a custom taxonomy, or simply "Posts" and "Categories"? Is there somewhere where we can see what's actually going wrong?
    – engelen
    Jun 17, 2014 at 7:52
  • i have updated my question
    – user54318
    Jun 17, 2014 at 9:08
  • I've updated my answer accordingly.
    – engelen
    Jun 17, 2014 at 11:56

Your code does not make sense to me, apart from having a syntax error. As your code stands, when you click on a post from a post/blog page, you are taken to the post's single view as it should. Only that post is displayed on single.php.

The problem starts when you click on the post links, doesn't matter if it is the previous or next post link. What is returned is all posts in that particular category when the next/previous page loads. That is how you coded your single.php, and why your post links doesn't work as you expect it to.

I would not use get_posts() to setup my loop on the single.php page. I would just use the normal proper loop. Please check out this page in the codex about Theme Development

Here is an example of a single.php that will work as expected

get_header(); ?>

<div id="main-content" class="main-content">

    <div id="primary" class="content-area">
        <div id="content" class="site-content" role="main">
                // Start the Loop.
                while ( have_posts() ) : the_post(); ?>

                    get_template_part( 'content', get_post_format() );

                    // Previous/next post navigation.
                    previous_post_link( '%link', 'Prev post in category', true );
                    next_post_link( '%link', 'Next post in category', true );

                    // If comments are open or we have at least one comment, load up the comment template.
                    if ( comments_open() || get_comments_number() ) {
        </div><!-- #content -->
    </div><!-- #primary -->

<?php get_sidebar( 'content' ); ?>
</div><!-- #main-content -->


As pointed out in the other answer, go and have a read on how to use the next_post_link and the previous_post_link

  • Thanks for your response can you tell me where the syntax error is in my code
    – user54318
    Jun 17, 2014 at 12:18
  • In this line echo $post->post_content, forgot ; Jun 17, 2014 at 12:19
  • Oh yes got it :)
    – user54318
    Jun 17, 2014 at 12:20
  • Please set debug to true in wp-config. This should help you a lot Jun 17, 2014 at 12:22
  • You should try what I said, your code can't work, with your code, as it is, it will simply reload the same page over and over with the post links Jun 17, 2014 at 12:24

I had the same issue PLUS I needed all that for custom post type & custom taxonomy. user54318 pointed me into the right direction, which is not capable to run cpt's, so i'll share my results here, too:

//get custom taxonomies.
$terms = wp_get_post_terms( get_the_ID(), 'product_cat' ); //last argument is the custom taxonomy. change to desired tax
//run through all terms and filter out the one, that i need. 
$stay_in = array();
foreach( $terms as $term ) :
/*this loop looks for a category, that is a children of category id 37. change to your needs. 
only importance is to build an array of term ids, to be included in the previous/next behaviour, so if you already know your ids, you could also use something like $stay_in = array( 43 ); and skip this whole loop..*/
    if ( $term->parent == 37 ) :
        $stay_in[] = $term->term_id;
        break; //break out the foreach, if found.
//get all post ids, that are in my defined category
$args = array(
    'post_type'         => 'product', //custom post type
    'posts_per_page'    => -1,
    'tax_query'         => array(
            'taxonomy'  => 'product_cat', // custom taxonomy
            'field'     => 'term_id',
            'terms'     => $stay_in,
            'operator'  => 'IN', //change to your needs.. IN, NOT IN, AND, EXISTS, NOT EXISTS
    'orderby'           => 'post_date',
    'order'             => 'ASC',
    'fields'            => 'ids', //only return the post ids, not the whole post-objects
$all_posts = new WP_Query( $args );
//search for the current post by its id and look for the previous / next ids
$this_index = array_search( $post->ID, $all_posts->posts );
$prev_id = $all_posts->posts[ $this_index - 1 ];
$next_id = $all_posts->posts[ $this_index + 1 ];
//echo links, if prevoius/next exists
if ( ! empty( $prev_id ) ) :
    echo '<a rel="prev" href="' . get_permalink( $prev_id ) . '">' . __( 'previous', 'your_theme_text_domain' ) . '</a>';

if ( ! empty( $next_id ) ) :
    echo '<a rel="next" href="' . get_permalink( $next_id ) . '">' . __( 'next', 'your_theme_text_domain' ) . '</a>';
  • Thank you, thank you thank you very much!!!! Jan 12, 2022 at 15:21
<?php next_post_link( '%link', '%title', TRUE, '0' , 'category' ); ?>
<?php previous_post_link( '%link', '%title', TRUE, '0' , 'category' ); ?>

Where 0 is the ID of the excluded category

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.