Bước 1: Register jquery

<?php
add_action('wp_enqueue_scripts', 'enqueue_infinite_scroll_scripts');
function enqueue_infinite_scroll_scripts(){
    if ( !is_shop() && !is_product_taxonomy() ) {
        return;
    } 

    global $wp_query;

    wp_enqueue_script(
        'infinite-scroll',
        THEME_URL . '/assets/js/infinite-scroll.js',
        ['jquery'],
        '1.0',
        true
    );

    wp_localize_script('infinite-scroll', 'lmproduct_obj', [
        'ajax_url'     => admin_url('admin-ajax.php'),
        'query_vars'   => json_encode($wp_query->query_vars),
        'nonce'        => wp_create_nonce( 'lmp_check_nonce' ),
        'max_num_pages' => $wp_query->max_num_pages,
    ]);        
}
?>

trong file infinite-scroll.js thêm đoạn code sau:

jQuery(document).ready(function ($) {
    var canLoad = true;
    var page = 2;
    // Load more product
    function loadMoreProducts() {
        if (typeof lmproduct_obj !== 'undefined') {
            const maxPages = parseInt(lmproduct_obj.max_num_pages);

            if (!canLoad || page > maxPages) return;

            canLoad = false; // Ngăn tải lặp lại

            $('.lmproduct-loading').addClass('is-loading');

            $.ajax({
                url: lmproduct_obj.ajax_url,
                type: 'POST',
                data: {
                    action: 'load_more_products',
                    page: page,
                    nonce: lmproduct_obj.nonce,
                    query_vars: lmproduct_obj.query_vars,
                },
                success: function (response) {
                    if (response.success && response.data) {
                        $('.products').append(response.data); // Append new product
                        page++;
                        canLoad = true; // allow load more

                        $('.lmproduct-loading').removeClass('is-loading');
                    }

                    // last page
                    if (page > maxPages) {
                        canLoad = false;
                        $('.lmproduct-loading').remove();
                    }
                },
                error: function () {
                    $('.lmproduct-loading').removeClass('is-loading');
                    canLoad = true;
                },
            });
        }
    }

    // Use Intersection Observer to detect when lmproduct-loading enters the viewport
    const observer = new IntersectionObserver(
        (entries) => {
            entries.forEach((entry) => {
                if (entry.isIntersecting) {
                    loadMoreProducts(); // Load more products when element appears
                }
            });
        },
        { root: null, rootMargin: '0px', threshold: 0.1 } // 10% of the elements appear
    );

    // Theo dõi phần tử lmproduct-loading
    const loadingElement = document.querySelector('.lmproduct-loading');
    if (loadingElement) {
        observer.observe(loadingElement);
    }
});

Bước 2: Remove default pagination

remove_action( 'woocommerce_after_shop_loop', 'woocommerce_pagination', 10 );
add_action( 'woocommerce_after_shop_loop', 'show_load_more_product_loading' );
function show_load_more_product_loading(){
    global $wp_query;
    
    if( $wp_query->max_num_pages > 1 ){
        echo '<div class="lds-ellipsis lmproduct-loading"><div></div><div></div><div></div><div></div></div>';
    }
}

Bước 3: Handle ajax loadmore product

function handle_load_more_products() {
    // phpcs:disable WordPress.Security.NonceVerification.Missing
    if ( !isset( $_POST['nonce'] ) ) {
        wp_send_json_error( 'missing_fields' );
        wp_die();
    }  

    // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    if( !wp_verify_nonce( wp_unslash( $_POST['nonce'] ), 'lmp_check_nonce' ) ){ 
        wp_send_json_error( 'bad_nonce' );
        wp_die();
    }

    $page = isset($_POST['page']) ? absint($_POST['page']) : 1;
    $query_vars = isset($_POST['query_vars']) ? json_decode(stripslashes($_POST['query_vars']), true) : [];

    $query_vars['paged'] = $page;
    $query_vars['post_status'] = 'publish';

    $products = new WP_Query($query_vars);

    if ($products->have_posts()) {
        ob_start();

        while ($products->have_posts()) {
            $products->the_post();
            wc_get_template_part('content', 'product');
        }
        wp_reset_postdata();

        wp_send_json_success(ob_get_clean());
    } else {
        wp_send_json_error('No more products'); 
    }

    wp_die();
}
add_action('wp_ajax_load_more_products', 'handle_load_more_products');
add_action('wp_ajax_nopriv_load_more_products', 'handle_load_more_products');

Bài viết liên quan

post-no-image

Update post meta ACF sử dụng Rest API WordPresss

post-no-image

Jquery ngăn không cho ô input type number nhập ký tự không hợp lệ

post-no-image

Hướng dẫn làm phần compare products trong Woocommerce

post-no-image

Add the Meta Box Upload Multiple Images and multiple metabox

post-no-image

Add the Meta Box Repeat

post-no-image

Kỹ thuật debounce trong javascript – Trì hoãn nhập từ khóa trong ô input