Using AJAX to load more products WooCommerce

拥有回忆 提交于 2021-02-20 00:42:49

问题


I am using AJAX to load more products on a WooCommerce archive. I have used AJAX to "Load More" once before on this page. I have used the same code for the most part, just altered the WP_Query arguments to suit my needs. I can't understand why my code doesn't work.

JS

/**
 * AJAX Load (Lazy Load) events
 */

$('#load-more').click( function(e){
    e.preventDefault();
    ajax_next_posts()
    $('body').addClass('ajaxLoading');
});

var ajaxLock = false; // ajaxLock is just a flag to prevent double clicks and spamming

if( !ajaxLock ) {

function ajax_next_posts() {

    ajaxLock = true;

    // How many posts there's total
    var totalPosts = parseInt( jQuery( '#found-posts' ).text() );

    // How many have been loaded
    var postOffset = jQuery( 'li.product' ).length

    // How many do you want to load in single patch
    var postsPerPage = 1;

    // Ajax call itself
    $.ajax({
        method: 'POST',
        url: leafshop.ajax_url,
        data: {
            action: 'ajax_next_posts',
            post_offset: postOffset,
            posts_per_page: postsPerPage,
            product_cat: cat_id
        },
        dataType: 'json'
    })
    .done( function( response ) { // Ajax call is successful
        // console.log( response );

        // Add new posts
        jQuery( '.product-grid' ).append( response[0] );

        // Log SQL query
        jQuery( '#query > pre' ).text( response[2] );

        // Update the count of total posts
        // jQuery( '#found-posts' ).text( response[1] );

        ajaxLock = false;

        console.log( 'Success' );

        $('body').removeClass('ajaxLoading');

        // How many posts there's total
        var totalPosts = parseInt( jQuery( '#found-posts' ).text() );
        console.log( "Total Posts: " + totalPosts );

        // How many have been loaded
        var postOffset = jQuery( 'li.product' ).length
            console.log( "Posts currently showing: " + postOffset );

        // Hide button if all posts are loaded
        if( totalPosts < postOffset + ( 1 * postsPerPage ) ) {
            jQuery( '#load-more' ).fadeOut();
        }

    })
    // .fail( function() {
    .fail( function(jqXHR, textStatus, errorThrown) { // Ajax call is not successful, still remove lock in order to try again

        ajaxLock = false;

        console.log(XMLHttpRequest);
        console.log(textStatus);
        console.log(errorThrown);

        console.log( 'Failed' );

    });
}
}

PHP

<?php

/**
 * Load next 12 products using AJAX
 */
function ajax_next_posts() {
    global $wpdb;
    // Build query
    $args = array(
        'post_type' =>  'product'
    );
// Get offset
if( !empty( $_POST['post_offset'] ) ) {

    $offset = $_POST['post_offset'];
    $args['offset'] = $offset;

    // Also have to set posts_per_page, otherwise offset is ignored
    $args['posts_per_page'] = 12;
}

// Get posts per page
if( !empty( $_POST['posts_per_page'] ) ) {
    // Also have to set posts_per_page, otherwise offset is ignored
    $args['posts_per_page'] = $_POST['posts_per_page'];
}

// Set tax query if on cat page
if( !empty( $_POST['product_cat'] ) ){
    $args['tax_query'] = array(
                            'taxonomy'          =>  'product_cat',
                            'terms'             =>  array( (int)$_POST['product_cat'] ),
                            'field'             =>  'id',
                            'operator'          =>  'IN',
                            'include_children'  =>  1
                        );
}

$count_results = '0';

$ajax_query = new WP_Query( $args );

// Results found
if ( $ajax_query->have_posts() ) {
    $count_results = $ajax_query->found_posts;

    // Start "saving" results' HTML
    $results_html = '';
    ob_start();

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

    // "Save" results' HTML as variable
    $results_html = ob_get_clean();
}

// Build ajax response
$response = array();

// 1. value is HTML of new posts and 2. is total count of posts
global $wpdb;
array_push ( $response, $results_html, $count_results, $wpdb->last_query );
echo json_encode( $response );

// Always use die() in the end of ajax functions
die();  
}
add_action('wp_ajax_ajax_next_posts', 'ajax_next_posts');
add_action('wp_ajax_nopriv_ajax_next_posts', 'ajax_next_posts');

The AJAX call runs successfully but doesn't return what I'd expect it to. I'd expect it to return the next product from the current category, instead it returns a product from a different category. The development site is accessible on http://leaf.kalodigital.co.uk and I have been using the "Black Tea" page in my testing. Any help would be greatly appreciated.


回答1:


Method

After some further research, I found that WooCommerce contains a class names WC_Poduct_Query. Following their documentation, found here, I rebuilt my query. This was working in the sense that it was querying for the correct products and returns the ones I'd expect it to as an array of WC_Product_Variable Objects. I proceeded to, within a foreach loop, use setup_postdata( $post ); to set the product Objects up so that I could use the wc_get_template_parts(); function to call the content-product.php template to format the output of the data. I found that this didn't work, although I couldn't figure to why this was the case, using setup-postdata(); was causing the object to turn into [{id:0,filter:raw},{id:0,filter:raw}]. I imagine this would be related to the WC_Product_Variable Objects not matching the expect format that setup_postdata(); usually expects from a WP_Post Object.

Nonetheless, I reverted to using WP_Query for my query, rebuilt the query script from scratch and, would you believe it, everything worked as expected to. Below is my working code to AJAX load the next "bunch" of products on any WooCommerce Archive page, at the click of a button.

Code

JS

/**
 * AJAX Load (Lazy Load) events
 */

 //--   Settings

// How many do you want to load each button click?
var postsPerPage = 12;

//--    /Settings

// How many posts there's total
var totalPosts = parseInt( jQuery( '#found-posts' ).text() );

// if( totalPosts == postOffset ) {
//  jQuery( '#load-more' ).fadeOut();
// }

$('#load-more').click( function(e){
    e.preventDefault();

    // Get current category
    var cat_id  =   $(this).data('product-category');


ajax_next_posts( cat_id );
    $('body').addClass('ajaxLoading');
});

var ajaxLock = false; // ajaxLock is just a flag to prevent double clicks and spamming

if( !ajaxLock ) {

    function ajax_next_posts( cat_id ) {

        ajaxLock = true;

        // How many have been loaded
        var postOffset = jQuery( 'li.product' ).length;

        // Ajax call itself
        $.ajax({
            method: 'POST',
            url: leafshop.ajax_url,
            data: {
                action: 'ajax_next_posts',
                post_offset: postOffset,
                posts_per_page: postsPerPage,
                product_cat: cat_id
            },
            dataType: 'json'
        })
        .done( function( response ) { // Ajax call is successful

            // Add new posts
            jQuery( '.product-grid' ).append( response[0] );

            // Update Post Offset
            var postOffset = jQuery( 'li.product' ).length;

            ajaxLock = false;

            console.log( 'Success' );

            $('body').removeClass('ajaxLoading');

            // How many posts there's total
            console.log( "Total Posts: " + totalPosts );

            // How many have been loaded
            var postOffset = jQuery( 'li.product' ).length
            console.log( "Posts on Page: " + postOffset );

            // Hide button if all posts are loaded
            if( ( totalPosts - postOffset ) <= 0 ) {
                jQuery( '#load-more' ).fadeOut();
            }

        })
        // .fail( function() {
        .fail( function(jqXHR, textStatus, errorThrown) { // Ajax call is not successful, still remove lock in order to try again

            ajaxLock = false;

            console.log(XMLHttpRequest);
            console.log(textStatus);
            console.log(errorThrown);

            console.log( 'Failed' );

        });
    }
}

PHP

<?php

/**
 * Load next 12 products using AJAX
 */
function ajax_next_posts() {
global $product;
// Build Query
    $args = array(
            'post_type'             =>  'product',
            'posts_per_page'        =>  (int)$_POST['posts_per_page'],
            'orderby'               =>  'title',
            'order'                 =>  'ASC',
            'offset'                =>  (int)$_POST['post_offset'],
        );

if( !empty( $_POST['product_cat'] ) ) {
    $args['tax_query'] = array(
                            'relation'  => 'AND',
                                array (
                                    'taxonomy'  =>  'product_cat',
                                    'field' =>  'slug',
                                    'terms' => $_POST['product_cat'],
                                    'operator'  =>  'IN'
                                ),
                        );
}

$count_results = '0';

$ajax_query = new WP_Query( $args );

// Results found
if( $ajax_query->have_posts() ){

    // Start "saving" results' HTML
    $results_html = '';
    ob_start();

    while( $ajax_query->have_posts() ) {

        $ajax_query->the_post();
        echo wc_get_template_part( 'content', 'product' );

    }
    wp_reset_postdata();

    // "Save" results' HTML as variable
    $results_html = ob_get_clean();

} else {

    // Start "saving" results' HTML
    $results_html = '';
    ob_start();

    echo "none found!";

    // "Save" results' HTML as variable
    $results_html = ob_get_clean();

}

// Build ajax response
$response = array();

// 1. value is HTML of new posts and 2. is total count of posts
array_push ( $response, $results_html );
echo json_encode( $response );

// Always use die() in the end of ajax functions
die();
}
add_action('wp_ajax_ajax_next_posts', 'ajax_next_posts');
add_action('wp_ajax_nopriv_ajax_next_posts', 'ajax_next_posts');

Use Cases

By refactoring the supplied AJAX code, it would be possible to turn this solution into an "infinite scrolling" system as opposed to a "Load More" button solution. Please feel free to reuse this code where it may see fit!



来源:https://stackoverflow.com/questions/52189258/using-ajax-to-load-more-products-woocommerce

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!