Next/Previous Product with custom order by price & products inside the product category

How to create next/prev buttons that are price sorted and give results inside the product category you are in?
This question has been asked multiple times and despite the multiple threads there wasn't an exact answer. Only relatively close ones that didn't do all of the above.

Below you will find my answer which works in my tests so far.

Topic woocommerce-offtopic next-post-link previous-post-link post-meta sort Wordpress

Category Web


After much trial and error i managed to refine the code above to clear all php notices that were created by the original code and make it work properly cause there were some mistakes in the previous code.
I am happy to share the solution to next/prev products in your product pages that wont show outofstock products and will be sorted by ASC price while showing results only from inside the product category you are in!

Give a thumbs up if you found it useful! :)

//generate_inside_site_container is a theme specific hook, you can use a woocommerce product hook instead and remove if ( is_product() ) {, in the next line

add_action('generate_inside_site_container', 'japs_prev_next_product', 1000);
function japs_prev_next_product() {
   if ( is_product() ) {
   global $post;
   $terms = get_the_terms( !empty($product->id), 'product_cat' );  
   foreach ($terms as $term) {
   if ($term->ID == !empty($category->cat_ID)) {
   $all_posts = new WP_Query(
      array(
         'post_type' => 'product',
         'meta_key' => '_price', // <-- CHANGE THIS
         'orderby' => 'meta_value_num',
         'order' => 'ASC',
         'post_status' => 'publish',
         'posts_per_page' => -1,
         'meta_query' => array(
            array(
                'key' => '_stock_status',
                'value' => 'outofstock',
                'compare' => '!=',
            )
         ),      
         'tax_query' => array(
                array(
                        'taxonomy' => 'product_cat',
                        'field'      => 'term_id',
                        'terms'    => $terms[0]->term_id
                     )
         )
      )
   );
       if ( $all_posts->post_count <= 1) {
           return;
       }
       break;
   }
   }
   foreach ($all_posts->posts as $key => $value) {
      if ($value->ID == $post->ID) {
         $nextID = $all_posts->posts[$key + 1]->ID;
         $prevID = $all_posts->posts[$key - 1]->ID;
         break;
      }
   }
   echo '<div>';
         if ($prevID) : ?>
            
            <a href="<?= get_the_permalink($prevID) ?>" rel="prev" class="prev" title="<?= get_the_title($prevID) ?>"><?= esc_attr__('Previous product') ?>
            </a>
   <?php endif; ?>
   <?php if ($nextID) : ?>
            <a href="<?= get_the_permalink($nextID) ?>" rel="next" class="next" title="<?= get_the_title($nextID) ?>"><?= esc_attr__('Next product') ?>
            </a>
   <?php endif; ?>
   <?php

   echo '</div>';
   }
}

I managed to modify an existing answer from a closely related thread to achieve this. You can find the answer from the related thread here. https://wordpress.stackexchange.com/a/365334/185141

add_action('woocommerce_before_single_product', 'elron_prev_next_product');

// and if you also want them at the bottom...
add_action('woocommerce_after_single_product', 'elron_prev_next_product');

function elron_prev_next_product() {
    
   global $post;
    
   echo '<div class="prev-next-buttons">';
   $terms = get_the_terms( $product->id, 'product_cat' );  
   foreach ($terms as $term) {
   if ($term->ID == $category->cat_ID) {
   $all_posts = new WP_Query(
      array(
         'post_type' => 'product',
         'meta_key' => '_price', // <-- CHANGE THIS
         'orderby' => 'meta_value',
         'order' => 'ASC',
         'post_status' => 'publish',
         'posts_per_page' => -1,
         'tax_query' => array(
                array(
                        'taxonomy' => 'product_cat',
                        'field'      => 'term_id',
                        'terms'    => $terms[0]->term_id
                     )
         )
      )
   );
       break;
   }
   }
   foreach ($all_posts->posts as $key => $value) {
      if ($value->ID == $post->ID) {
         $nextID = $all_posts->posts[$key + 1]->ID;
         $prevID = $all_posts->posts[$key - 1]->ID;
         break;
         wp_reset_postdata();
      }
   }

   if ($prevID) : ?>
      <a href="<?= get_the_permalink($prevID) ?>" rel="prev" class="prev" title="<?= get_the_title($prevID) ?>"><?= esc_attr__('Previous product') ?></a>
   <?php endif; ?>
   <?php if ($nextID) : ?>
      <a href="<?= get_the_permalink($nextID) ?>" rel="next" class="next" title="<?= get_the_title($nextID) ?>"><?= esc_attr__('Next product') ?></a>
   <?php endif; ?>
   <?php

   echo '</div>';
}

I know i was searching for a way to make next/prev button on my product pages that were sorted by price and gave products only inside the product category i was on, for a long time, if you did as well give an upvote! :)

EDIT: You can also limit the query created to output products that aren't outofstock

$all_posts = new WP_Query(
      array(
         'post_type' => 'product',
         'meta_key' => '_price', // <-- CHANGE THIS
         'orderby' => 'meta_value',
         'order' => 'ASC',
         'post_status' => 'publish',
         'posts_per_page' => -1,
         'meta_query' => array(
            array(
                'key' => '_stock_status',
                'value' => 'outofstock',
                'compare' => '!=',
            )
         ),      
         'tax_query' => array(
                array(
                        'taxonomy' => 'product_cat',
                        'field'      => 'term_id',
                        'terms'    => $terms[0]->term_id
                     )
         )
      )
   );

EDIT 2: Although the above code works just fine in all my tests, there are 2 notices generated from wp_debug

Notice: Undefined variable: product in /public/wp-content/themes/generatepress_child/functions.php on line 2098

Notice: Trying to get property 'id' of non-object in /public/wp-content/themes/generatepress_child/functions.php on line 2098

Notice: Undefined variable: category in /public/wp-content/themes/generatepress_child/functions.php on line 2100

Notice: Trying to get property 'cat_ID' of non-object in /public/wp-content/themes/generatepress_child/functions.php on line 2100

2098 line: $terms = get_the_terms( $product->id, 'product_cat' );
2100 line: if ($term->ID == $category->cat_ID) {

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.