As you are aware, the WooCommerce Single Product Page typically displays a fixed number of related products (usually 4). However, although you can adjust the number of related products through code, there isn’t a built-in setting to replace this with a “LOAD MORE” button.

My objective is to enable users to view as many Related Products as they desire without needing to reload the page, thereby allowing them to explore more potential matches and potentially increase order placements.

I spent the entire morning working on this, but it’s not yet complete. There are two minor issues: (1) the “Load More” button does not hide when there are no more related products to display, and (2) after exhausting the related products of the current item (by clicking the load more button one or more times), the Ajax function continues to display the last related product instead of none. Please feel free to contribute if you’d like to assist!

With that said, let’s explore how to implement an Ajax “load more” feature. This can also be adapted for other projects (e.g., “load more blog posts”), as once you grasp how Ajax operates, you can accomplish various exciting tasks without needing to refresh the page.

Enjoy!

function fixelar_related_products_load_more( $html ) {
 
   // ONLY TARGET THE RELATED PRODUCTS LOOP
   if ( wc_get_loop_prop( 'name' ) === 'related' ) {
    
      // SHOW BUTTON
      $html .= '<a class="button loadmore">Load More Related Products</a>';
 
      // TRIGGER 'ajax_loadmore' ACTION ON CLICK
      // AND APPEND MORE RELATED PRODUCTS 
      wc_enqueue_js( "
         var page = 2;
         var ajaxurl = '" . admin_url( 'admin-ajax.php' ) . "';
         $('body').on('click', '.loadmore', function(evt) {
            var data = {
               'action': 'ajax_loadmore',
               'page': page,
               'product_id': " . get_queried_object_id() . ",
            };
            $.post(ajaxurl, data, function(response) {
               if(response != '') {
                  $('.related .products ').append(response);
                  page++;
               }
            });
         });
      " );
   }
   return $html;
}
add_filter( 'woocommerce_product_loop_end', 'fixelar_related_products_load_more' );
 
 
function fixelar_related_products_load_more_event() {
 
   // GET PARAMETERS FROM POSTED DATA
   $paged = $_POST['page'];
   $product_id = $_POST['product_id'];
 
   // DEFINE USEFUL QUERY ARGS:
   // 1. CURRENT PRODUCT
   $product = wc_get_product( $product_id );
 
   // 2. PAGINATION AND SORTING
   $args = array(
      'posts_per_page' => 3,
      'paged' => $paged,
      'orderby' => 'id',
      'order' => 'desc',
   );
 
   // 3. IDS TO EXCLUDE: ON LOAD MORE, WE DONT WANT THE FIRST 3 RELATED PRODUCTS AGAIN
   // SO WE APPLY AN OFFSET TO GET THE "NEXT 3" PRODUCTS
   $exclude = array_slice( array_map( 'absint', array_values( wc_get_related_products( $product->get_id(), -1 ) ) ), 0 , $args['posts_per_page'] * ( $paged - 1 ) );
 
   // LETS CALCULATE AND SORT RELATED PRODUCTS
   $related_products = array_filter( array_map( 'wc_get_product', wc_get_related_products( $product->get_id(), $args['posts_per_page'], $exclude + $product->get_upsell_ids() ) ), 'wc_products_array_filter_visible' );
   $related_products = wc_products_array_orderby( $related_products, $args['orderby'], $args['order'] );
 
   // LETS DISPLAY THEM
   foreach ( $related_products as $related_product ) {
      $post_object = get_post( $related_product->get_id() );
      setup_postdata( $GLOBALS['post'] =& $post_object );
      wc_get_template_part( 'content', 'product' );
   }  
   wp_die();
 
}
add_action( 'wp_ajax_nopriv_ajax_loadmore', 'fixelar_related_products_load_more_event' );
add_action( 'wp_ajax_ajax_loadmore', 'fixelar_related_products_load_more_event' );