Next/Previous Post Links in Same Top Level Category

Next/Previous Post Links in Same Top Level Category

In WordPress it’s often desirable to restrict pagination to posts within the current posts’ category (or custom taxonomy); usually because of particular ordering requirements. For instance, when it wouldn’t make sense to mix posts of a certain category with others.

The easiest way to display next/previous post pagination on your single.php template (or single-custom-post-type.php template) is to use the next_post_link() and previous_post_link() functions. These both display the relevant posts adjacent to the current post.

But what if you want to paginate posts within the same category? Or, extending this further, within the same top level category.

How to Keep Post Pagination in Same Parent Category

By default WordPress will paginate between the first category the post is assigned to alphabetically. Probably not you’re after as navigating back and forth between posts will provide an inconsistent order.

The next_post_link() and previous_post_link() functions have built in parameters that we can make use of. First of all, to ensure the next and previous adjacent posts are within the same category (or taxonomy) we can set the $in_same_term option to TRUE:

<nav class="pagination">
   <ul>
      <li class="prev"><?php previous_post_link( '%link', 'Previous Post', TRUE ); ?></li>
      <li class="next"><?php next_post_link( '%link', 'Next Post', TRUE ); ?></li>
   <ul>
</nav>

Yet what if you want to paginate between posts within top level categories only? I came across this in a recent WordPress project using a custom post type (event) and custom taxonomies (event-category) to organise event data. The event category structure was as follows:

  • Top Level Event Category 1

    • Child Event Category 1
    • Child Event Category 2
    • Child Event Category  3
  • Top Level Event Category 2

    • Child Event Category 4
    • Child Event Category 5
    • Child Event Category 6

An event is exclusively categorised in one of the top level event categories and in up to three child event categories. Although $in_same_term is set to TRUE, the next_post_link() and previous_post_link() functions were linking to adjacent posts in any of the event categories the current event was in.

From the WordPress Codex on next_post_link():

If the post is in both the parent and subcategory, or more than one term, the next post link will lead to the next post in any of those terms.

Therefore not what we want when trying to retain a uniform order of events.

Exclude All Categories That Aren’t Top Level

The next_post_link() and previous_post_link() functions have another parameter that can be used together with $in_same_term$excluded_terms. This can be passed an array of, or string of comma-separated taxonomy term IDs to exclude.

This can be used to link to the next/previous post within the same category, unless that category is within the excluded categories.

In my case I used this to exclude any child level categories from my pagination, as I wanted to display events in order of either top level event category.

I wrote a custom function (in the theme’s functions.php file) that would return all term IDs of the current event post that aren’t top level:

function get_excluded_event_categories() {
   // Get event categories of current event
   $current_event_cats = wp_get_post_terms( get_the_ID(), 'event-category' );
   // Declare array to store excluded sub event categories
   $excluded_sub_event_cats = [];
   // Loop through current event categories
   foreach( $current_event_cats as $cat ) {
      // Check if current category has a parent category
      $parent_cat = $cat->parent;
      if($parent_cat !== 0) {
          // If it does, add it's term ID to the excluded array
          array_push($excluded_sub_event_cats, $cat->term_id);
      }
   }
   return $excluded_sub_event_cats;
}

To give me the required pagination order for the events in my single-event.php template, I could subsequently call my function here:

<nav class="pagination">
   <ul>
      <li class="prev"><?php previous_post_link( '%link', 'Previous Post', TRUE, get_excluded_event_categories(), 'event-category' ); ?></li>
      <li class="next"><?php next_post_link( '%link', 'Next Post', TRUE, get_excluded_event_categories(), 'event-category' ); ?></li>
   <ul>
</nav>

In Summary

Most of all it’s important to note that the above is a solution to a problem I encountered on a specific project. The code should be adapted to suit your needs. This will probably be straightforward and changing the taxonomy name should work for most cases.

You’ll also want to give the custom function a more appropriate name if you’re not dealing with events.

I hope this helps someone out!

Posted in: