WooCommerce 使用 Ajax 将多个商品添加到购物车

WooCommerce Adding multiple items to the cart with Ajax

提问人:Ping 提问时间:3/23/2021 最后编辑:LoicTheAztecPing 更新时间:2/16/2023 访问量:1687

问:

我使用最新版本的 Wordpress 和 Woocommerce。我有一些 JavaScript 可以遍历 class 的 DOM 元素并从带有 class 的元素中获取属性,并将该项目添加到购物车中:.selectableproduct_id.selected

// selects the elements
$('.next').on('click', function() {
    var parent  = $(this).closest('.panel');
    var selectables = parent.children('.option.selectable.selected');

    $(selectables).each(function() {
        var product = $(this).attr('product');
        add_to_cart(product, 1);    
    });
}

// add to cart AJAX
function add_to_cart(product_id, qty) {
    $.ajax({
        type: "POST",
        url: base_url + '/wp-admin/admin-ajax.php',
        data: {action : 'cl_add_to_cart', 'product_id': product_id, 'qty': qty},
        success : function(response) {
            console.log(response);
        }
    });
}

我在函数.php中有一个PHP函数

add_action('wp_ajax_cl_add_to_cart', 'cl_add_to_cart');
add_action('wp_ajax_nopriv_cl_add_to_cart', 'cl_add_to_cart');

function cl_add_to_cart() {
    global $woocommerce;
    $product_id   = trim($_POST['product_id']);
    $qty = !empty($_POST['qty']) ? trim($_POST['qty']) : 1;
    $added = WC()->cart->add_to_cart($product_id, $qty);
    echo json_encode($added);
}

AJAX 调用很好地击中了 PHP 函数 - 我可以回显$added这给了我一个哈希值。如果我在可选变量中有两个或更多项目,它们都会命中 PHP 函数(我得到两个哈希值),但只有第一个被添加到购物车中。

我一辈子都想不通为什么。有什么想法吗?

php jquery ajax wordpress woocommerce

评论

0赞 Bhautik 3/23/2021
我测试了你的代码,它对我来说工作正常。您确定您不是每次都添加相同的产品,因为如果您将相同的产品添加到购物车,那么它将增加该产品的数量,而不会被视为新产品。

答:

3赞 LoicTheAztec 3/23/2021 #1

最好使用 Ajax 一次性发送所有要添加的项目,而不是在多个 Ajax 请求中单独发送它们,这样会更轻、更有效。

您需要确保它按预期工作。$(selectables).each(function() { // ... });

以下命令将为单击事件发送唯一的 Ajax 请求。

jQuery 代码

// Multi Ajax adda to cart
function multiAddToCart( productsData ) {
    $.ajax({
        url: base_url + '/wp-admin/admin-ajax.php',
        type: 'POST',
        dataType: 'JSON',
        data: {
            'action': 'multi_add_to_cart',
            'items' : Object.assign({}, productsData)
        },
        success : function(response) {
            $(document.body).trigger('wc_fragment_refresh'); // Refresh cart fragments
            console.log(response);
        },
        error : function(error) {
            console.log(error);
        }
    });
}

$('.next').on('click', function() {
    var productsData = [];
    var parent  = $(this).closest('.panel');
    var selectables = parent.children('.option.selectable.selected');

    $(selectables).each(function() {
        var productId = $(this).attr('product');
        productsData.push({'id': productId, 'qty': 1});
    });
    // Check the data before (number of items found)
    console.log(productsData); 

    multiAddToCart( productsData );
});

php 接收器函数:

add_action('wp_ajax_multi_add_to_cart', 'multi_ajax_add_to_cart');
add_action('wp_ajax_nopriv_multi_add_to_cart', 'multi_ajax_add_to_cart');
function multi_ajax_add_to_cart() {
    if (isset($_POST['items']) ) {
        $item_keys = array();

        foreach( $_POST['items'] as $item ) {
            if( isset($item['id']) ) {
                $item_qty  = isset($item['qty']) && $item['qty'] > 1 ? $item['qty'] : 1;
                $item_keys[] = WC()->cart->add_to_cart($item['id'], $item_qty);
            }
        }
        echo json_encode($item_keys); // Send back cart item keys
    }
    die();
}

代码进入活动子主题(或活动主题)的函数.php文件。经过测试并有效。

它应该可以一次添加所有项目。

评论

0赞 Ping 3/24/2021
好的,谢谢。不同之处在于有多个 next 按钮,比如 8,因此我需要在 click 事件之外抽象 productsData,以便它持续存在。
0赞 Stefan S 2/12/2023 #2

主要答案并没有真正解决根本问题。此外,并不总是可以同时添加产品。您可能有一个订单,用户可以在其中快速单击多个不同的项目。

问题来了: WooCommerce 添加到购物车功能通过将变量设置为特定项目来工作。$this->cart_contents

在 AJAX 中使用时会出现此问题,因为多个此类add_to_cart函数同时运行。发生的情况是,一个函数将在前一个函数启动但未完成之后启动。WC()->cart->add_to_cart()

结果是第二个函数设置购物车内容,而不知道它缺少上一个函数刚刚添加的产品。

现在的解决方案是:让 javascript 等到上一个函数用递归函数完成:

(这段代码并不完整,它只是说明了这个想法):

add_cart_clear = 'yes';

function order_form_add(datavar, qty){

    if (add_cart_clear === 'yes'){ // proceed only if clear
        
        add_cart_clear = 'no'; // new function started, not clear
        $.post(ajaxurl, data, function(response){ // function ended, it's clear again
            add_cart_clear = 'yes';                             
        });

    } else {

        setTimeout(function(){
            order_form_add(data, qty); // if not ready, wait 100ms and try again
        }, 100);
    }
    
}