使用 AJAX 加载更多产品 WooCommerce

E.O*_*wen 1 php ajax wordpress jquery woocommerce

我正在使用 AJAX 在 WooCommerce 存档中加载更多产品。我之前在此页面上曾使用 AJAX 来“加载更多” 。我大部分使用了相同的代码,只是更改了WP_Query参数以满足我的需要。我不明白为什么我的代码不起作用。

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' );

    });
}
}
Run Code Online (Sandbox Code Playgroud)

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');
Run Code Online (Sandbox Code Playgroud)

AJAX 调用成功运行,但没有返回我期望的结果。我希望它返回当前类别的下一个产品,而不是返回不同类别的产品。开发站点可在http://leaf.kalodigital.co.uk上访问,我在测试中一直使用“红茶”页面。任何帮助将不胜感激。

E.O*_*wen 5

方法

经过进一步研究,我发现 WooCommerce 包含一个 class names WC_Poduct_Query。按照他们的文档,找到here,我重建了我的查询。从某种意义上说,这有效的,它正在查询正确的产品并将我期望的产品作为WC_Product_Variable对象数组返回。我继续在foreach循环中使用setup_postdata( $post );来设置产品对象,以便我可以使用该wc_get_template_parts();函数调用content-product.php模板来格式化数据的输出。我发现这不起作用,虽然我不知道为什么会这样,但使用setup-postdata();会导致对象变成[{id:0,filter:raw},{id:0,filter:raw}]. 我想这与WC_Product_Variable对象不匹配setup_postdata();通常期望的期望格式有关WP_Post 目的。

尽管如此,我恢复使用WP_Query我的查询,从头开始重建查询脚本,你相信吗,一切都按预期工作。下面是我的工作代码,通过单击按钮,AJAX 在任何WooCommerce 存档页面上加载下一个“一堆”产品。

代码

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' );

        });
    }
}
Run Code Online (Sandbox Code Playgroud)

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');
Run Code Online (Sandbox Code Playgroud)

用例

通过重构提供的 AJAX 代码,可以将此解决方案变成“无限滚动”系统,而不是“加载更多”按钮解决方案。请随意在它认为合适的地方重用此代码!