WooCommerce pagination on single product pages – but only inside parent category

I would like to put pagination on each single product page in WooCommerce so that a user can move between products in that category easier than having to go back out to the main category page every time.

I know it’s possible to use the standard WordPress pagination links like…

Read More
<?php previous_post_link('&laquo; %link'); ?>
<?php next_post_link('%link &raquo;'); ?>

This works if I want to page through all products, but I only want to page through products that are within the category I’m in. Does anyone know how I can limit this so products outside this category aren’t included?

I’ve tried using the in_same_term parameter as mentioned in the WordPress codex to get the links only showing if the next/prev product is in the same category, but it’s returning an integer for some reason. Here’s the code I’m using…

<?php next_post_link( '%link', '%title', TRUE, '' ); ?>

This returns nothing at all even though it follows the Codex structure. I’ve also tried…

<?php next_post_link( '%link %title', TRUE, '' ); ?>

And this is what I’m getting in return…

1 %title

I’m stumped where to go next.

Related posts

Leave a Reply

1 comment

  1. Here is a function that I have recently written that also does the job and is quite flexible

    THE IDEA:

    You first need to get the current post id, which I get through get_queried_object_id(). The post ID will be used to retrieve:

    • The post terms the post belongs to with wp_get_post_terms(). To speed things up, only the ID’s of the terms will be returned. The first ID will be used (you can modify the code here to decide which term will be used if a post have more than one term) and this will be used to retrieve all the posts which has this certain term

    • The post ID’s of the posts that is directly adjacent to this post to determine and retrieve the next and previous post from this one

    All the info above will be used in a tax_query with get_posts to retrieve all the posts that shares the term from the current post. In the function, the default taxonomy is category and the post_type is set to any to get all the posts that has this specific term

    Again, to make the code faster and to safe on resources, we only going to get the post ID’s as this is all that is needed

    Now comes the important parts of the code. We now need to determine the following:

    • The current position of the current post in the returned array of post ID’s from the custom get_posts query. The function used here is array_search

    • If there is a post before or after this post (next or previous posts, the definitions are the same as for the build in functions next_post_link() and previous_post_link()), get the ID’s of these posts

    • Use the ID’s with get_post to retrieve the next and previous post’s titles from the current post

    Lastly will be to return the links. I have set messages if the current post is either the first or last post in the array and there are no next or previous post. You can decide what you want to do here, and for all that matters, the rest of the code

    To make the code even faster and more efficient, I have made use of the Transient API which you can read further on. I have also used the transition_post_status action hook to hook a function to delete these transients whenever the post status of a post change. This includes new posts being published, post being updated and post deleted/undeleted

    THE CODE:

    Here is the code. This goes into your functions.php

    function get_post_link( $taxonomy = 'category', $post_type = [ 'any' ] ) {
    
        $id             = get_queried_object_id(); // Get the current post ID
        $transient_id   = 'post_number_' . md5( $id . $taxonomy . implode( ',', $post_type ) ); //Create a unique transient id
    
        if ( false === ( $links = get_transient( $transient_id ) ) ) {
    
            // Get the terms a post belongs to
            $terms = wp_get_post_terms( $id, $taxonomy, array( 'fields' => 'ids' ) ); 
    
            // Use a tax_query to get all posts from the given term
            // Just retrieve the ids to speed up the query
            $post_args = [ 
                'post_type'         => $post_type,
                'fields'            => 'ids',
                'posts_per_page'    => -1,
                'tax_query'         => [
                    [
                        'taxonomy'          => $taxonomy,
                        'field'             => 'term_id',
                        'terms'             => $terms[0],
                        'include_children'  => false,
                    ],
                ],
    
            ];
    
            // Get all the posts having the given term from all post types
            $q = get_posts( $post_args );
    
            //Get the current post position. Will be used to determine next/previous post
            $current_post_position = array_search( $id, $q );
    
            // Get the previous/older post ID
            if ( array_key_exists( $current_post_position + 1 , $q ) ) {
                $previous = $q[$current_post_position + 1];
            }
    
            // Get post title link to the previous post
            if( isset( $previous ) ) {
                $previous_post      = get_post( $previous );
                $previous_post_link = get_permalink( $previous );
                $previous_title     = '<a href="' . $previous_post_link . '">' . $previous_post->post_title . '</a></br>';
            }
    
            // Get the next/newer post ID
            if ( array_key_exists( $current_post_position - 1 , $q ) ) {
                $next = $q[$current_post_position - 1];
            }
    
            // Get post title link to the next post
            if( isset( $next ) ) {
                $next_post      = get_post( $next );
                $next_post_link = get_permalink( $next );
                $next_title     = '<a href="' . $next_post_link . '">' . $next_post->post_title . '</a></br>';?><pre><?php var_dump($next_title); ?></pre><?php 
    
            }
    
            // The returned post links 
            if( isset( $previous_title, $next_title ) ) {
    
                $links = [
                    'previous_post' => $previous_title, 
                    'next_post'     => $next_title, 
                ];
    
            }elseif( !isset( $previous_title ) && $next_title ) {
    
                $links = [
                    'previous_post' => 'You are currently viewing the newest post', 
                    'next_post'     => $next_title, 
                ];
    
            }elseif( $previous_title && !isset( $next_title ) ) {
    
                $links = [
                    'previous_post' => $previous_title, 
                    'next_post'     => 'You are currently viewing the last post', 
                ];
    
            }
    
            set_transient( $transient_id, $links, 7 * DAY_IN_SECONDS );
        }
    
        return (object)$links;
    }
    
    add_action( 'transition_post_status', function ( $new_status, $old_status, $post )
    {
    
            global $wpdb;
            $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient%_post_number_%')" );
            $wpdb->query( "DELETE FROM $wpdb->options WHERE `option_name` LIKE ('_transient_timeout%_post_number_%')" );
    
    }, 10, 3 );
    

    HOW TO USE:

    You can now use the code as follows in you single.php. The default taxonomy is category and post type is any. If your custom taxonomy is called mytax, you can use the code like this

    if( function_exists( 'get_post_link' ) ) {          
        $post_links = get_post_link( 'mytax' );
        echo $post_links->previous_post . '</br>' . $post_links->next_post;
    }