【问题标题】:WooCommerce - How can I add multiple, different products to cart using ajax with same add-to-cart-Button?WooCommerce - 如何使用具有相同添加到购物车按钮的 ajax 将多个不同的产品添加到购物车?
【发布时间】:2019-08-31 18:16:25
【问题描述】:

我正在尝试使用 ajax 一键单击将多个不同的产品添加到购物车。 AddToCart-Button 存在于非 WooCommerce 页面模板中。

我认为可以通过等待第一个 ajax 发布成功来解决,然后迭代到下一个产品,依此类推,直到所有选定的产品都完成 ajax 发布,然后最终应该会成功。

我只是不知道我是怎么做到的 :) 你知道怎么做吗?

这是我的产品表单 html:

<form id="buy-tickets" action="https://mydomain.de/cart/" class="cart" method="post" enctype="multipart/form-data" novalidate="">
<input type="hidden" name="product_id[]" value="5353"><div class="terminMain"><div class="terminDate">28.09.2019 Event Name 1<p><b>(Noch Plätze frei)</b></p></div><div class="personenNumber" id="personenNumber1">
                        <div class="inputField">
                            <input type="button" value="-" class="qtyminus" field="quantity_5353" id="qtyminus1">
                            <input type="text" id="quantity_5353" name="quantity_5353" value="0" class="qty">
                            <input type="button" value="+" class="qtyplus" field="quantity_5353" id="qtyplus1">
                            <input type="hidden" name="stock" value="1985" field="stock">
                        </div>
                    </div></div><input type="hidden" name="product_id[]" value="5354"><div class="terminMain"><div class="terminDate">31.03.2026 Event Name 2<p><b>(Noch Plätze frei)</b></p></div><div class="personenNumber" id="personenNumber2">
                        <div class="inputField">
                            <input type="button" value="-" class="qtyminus" field="quantity_5354" id="qtyminus2">
                            <input type="text" id="quantity_5354" name="quantity_5354" value="0" class="qty">
                            <input type="button" value="+" class="qtyplus" field="quantity_5354" id="qtyplus2">
                            <input type="hidden" name="stock" value="1989" field="stock">
                        </div>
                    </div></div>            <div class="buchenBtn">
                <div class="btns woocommerce add-to-cart"> 
                            <button type="submit" name="ticket_process" value="1" class="ajax_add_to_cart single_add_to_cart_button btn added" id="buchen-wootickets">Buchen</button> <a href="https://mydomain.de/cart/" class="added_to_cart wc-forward" title="Warenkorb anzeigen">Show Cart</a>

                </div>
            </div>
</form>

这是 jQuery:

(function ($) {
    $( document ).on( 'click', '.single_add_to_cart_button', function(e) {
        e.preventDefault();
        var tickets = $('#buy-tickets input[name="product_id[]"]');
        var ticketsData = [];
        var $this, ticketId, ticketQty, ticketProd;  
        tickets.each(function() {
                    $this = $( this );
                    id = $this.val();
                    ticketQty = $('#quantity_'+id).val();
                    if(ticketQty > 0){
                        ticketProd = {
                            action: 'woocommerce_ajax_add_to_cart', 
                            product_id: id, 
                            product_sku: '',
                            quantity: ticketQty,
                            variation_id: 0,
                        };
                        ticketsData.push(ticketProd);
                    }   
            });
        console.log('tickets: ', ticketsData);

        var $thisform = $('#buy-tickets');
        var $thisbutton = $(this);

        $.each(ticketsData, function(index, value){
            $.each(this, function (index, value) {
                console.log(index + " :: " + value);
            });
            $(document.body).trigger('adding_to_cart', [$thisbutton, this]);

            $.ajax({
                type: 'post',
                url: wc_add_to_cart_params.ajax_url,
                data: this,
                beforeSend: function (response) {
                    $thisform.addClass('loading');
                    $thisbutton.removeClass('added');
                },
                complete: function (response) {
                    $thisform.removeClass('loading');
                    $thisbutton.addClass('added');
                },
                success: function (response) {

                    if (response.error & response.product_url) {
                        window.location = response.product_url;
                        return;
                    } else {
                        $(document.body).trigger('added_to_cart', [response.fragments, response.cart_hash, $thisbutton]);
                    }
                },
            });

            return false;

        });
    });
})(jQuery);

以及处理我的 Ajax 的 php 函数:

add_action( 'wp_ajax_woocommerce_ajax_add_to_cart', 'tec_woocommerce_ajax_add_to_cart' );
add_action( 'wp_ajax_nopriv_woocommerce_ajax_add_to_cart', 'tec_woocommerce_ajax_add_to_cart' );

function tec_woocommerce_ajax_add_to_cart() {

            $product_id        = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_POST['product_id'] ) );
            $quantity          = empty( $_POST['quantity'] ) ? 1 : wc_stock_amount( $_POST['quantity'] );
            $variation_id      = absint( $_POST['variation_id'] );
            $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
            $product_status    = get_post_status( $product_id );

    if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity, $variation_id ) && 'publish' === $product_status ) {

        do_action( 'woocommerce_ajax_added_to_cart', $product_id );

        if ( 'yes' === get_option( 'woocommerce_cart_redirect_after_add' ) ) {
            wc_add_to_cart_message( array( $product_id => $quantity ), true );
        }

        WC_AJAX::get_refreshed_fragments();
    } else {

        $data = array(
            'error'       => true,
            'product_url' => apply_filters( 'woocommerce_cart_redirect_after_error', get_permalink( $product_id ), $product_id ),
        );

        echo wp_send_json( $data );
    }

            wp_die();
}

代码已经运行良好,只是罪魁祸首:它只是将 1 个产品 ID 及其设置数量添加到购物车并在此之后停止,即使通过设置其他产品的数量也选择了多个产品。

我正在寻找一种解决方案,它将根据每个产品设置的任何数量将所有选定的产品添加到购物车。

有什么帮助吗?建议?

【问题讨论】:

  • 您没有将所有产品添加批处理到一个 AJAX 请求中是否有原因?我认为这不仅会更有效率,而且还会简化逻辑。关于为什么给定代码不起作用 - 浏览器网络日志是否显示已发送多个 AJAX 请求?
  • 嗯,这实际上是我想要的:D,但不知道如何将产品添加到一个 Ajax 请求中。
  • 您可以使用 JSON.stringify() 将 JavaScript 数组作为字符串发送到 WooCommerce,然后使用 PHP 的 json_decode() 将其解压缩到 PHP 数组中。
  • 您能否通过提供代码答案进一步说明这一点?会非常好!
  • 是的,但不是立即。如果您不想使用 JSON,我相信您可以直接将数组作为 POST 参数发送。我的安装目前没有 WooCommerce,所以我需要先激活它,然后才能测试代码,所以我不能立即执行此操作,但我会处理它,因为我发现这是一个有趣的问题。

标签: php jquery ajax wordpress woocommerce


【解决方案1】:

以下代码已添加到我的functions.php 中。它展示了如何在单个 AJAX 请求中将多个产品发送到 WooCommerce。它只是一个框架,您需要添加实际将产品添加到购物车的 PHP 代码。

add_action( 'woocommerce_after_main_content', function() {
?>
<button id="saskia-add_multiple_products" style="background-color: cyan; border: 3px solid red; margin:50px;">
    Add Multiple Products
</button>
<script>
    jQuery( 'button#saskia-add_multiple_products' ).click( function() {
        var productsToAdd = [
            { id: 2650, quantity: 1 },
            { id: 3060, quantity: 2 }
        ];
        // There are multiple ways of sending complex data from JavaScript to WordPress
        // JavaScript: JSON.stringify(), jQuery: .serialize() or the following bare-bones
        // way which is wordy but probably the easiest to understand. Since, your data
        // is already in a HTML form .serialize() is probably the best but I am too lazy
        // to make a form so I am testing from data in a JavaScript array.
        var data = { action: 'saskia_add_multiple_products', id: [], quantity: [] };
        jQuery.each(productsToAdd, function( index, value ) {
            data.id[index]       = value.id;
            data.quantity[index] = value.quantity;
        } );
        jQuery.post( 'http://localhost/wp-admin/admin-ajax.php', data, function(data){ /* process success response */} );
    } );
</script>
<?php
} );

add_action( 'wp_ajax_saskia_add_multiple_products', function() {
    error_log( 'ACTION:wp_ajax_nopriv_saskia_add_multiple_products:$_POST=' . print_r( $_POST, TRUE ) );
    for ( $i = 0; $i < count( $_POST['id'] ); $i++ ) {
        $product_id = $_POST['id'][$i];
        $quantity   = $_POST['quantity'][$i];
        error_log( 'ACTION:wp_ajax_nopriv_saskia_add_multiple_products:$product_id=' . $product_id );
        error_log( 'ACTION:wp_ajax_nopriv_saskia_add_multiple_products:$quantity='   . $quantity );
        /* add each individual product to cart */
    }
    // return the update cart HTML fragments
    WC_AJAX::get_refreshed_fragments();
} );

这个 HTTP 请求的 $_POST 是:

$_POST=Array
(
    [action] => saskia_add_multiple_products
    [id] => Array
        (
            [0] => 2650
            [1] => 3060
        )

    [quantity] => Array
        (
            [0] => 1
            [1] => 2
        )

)

您可能想在表单上尝试 jQuery 的 .serialize()。我认为这将是最简洁的解决方案。如果这还不够,请告诉我。现在我已经激活了 WooCommerce,很容易向这个答案添加更多详细信息。

附录

我在您的 HTML 表单上尝试了 jQuery 的 .serialize()。首先,您必须添加一个隐藏的 HTML &lt;input&gt; 元素以提供 AJAX 操作参数:

<form id="buy-tickets" action="https://mydomain.de/cart/" class="cart" method="post" enctype="multipart/form-data" novalidate="">
    <input type="hidden" name="action" value="saskia_add_multiple_products" />
    ...
</form>

使用 .serialize() 的 jQuery AJAX 调用是:

jQuery.post( 'http://localhost/wp-admin/admin-ajax.php',
    jQuery('form#buy-tickets').serialize(),
    function(data) { /* process success response */}
);

这会发送以下 $_POST:

$_POST=Array
(
    [action] => saskia_add_multiple_products
    [product_id] => Array
        (
            [0] => 5353
            [1] => 5354
        )

    [quantity_5353] => 0
    [stock] => 1989
    [quantity_5354] => 0
)

我不太明白其中的一些,但我认为如果你调整你的表单,你可以获得 jQuery 的 .serialize() 来批处理你的产品。考虑改变

name="quantity_5353" -> name="quantity[]"
name="quantity_5354" -> name="quantity[]"

我认为您不需要发送“库存”。我也不会将产品数据直接硬编码到表单中,而是使用 PHP 变量,以便表单可以再次用于不同的产品。理想情况下,表单中产品的 HTML 应该使用 foreach ( $products as $product ) { ... } 生成,因此表单可以适用于任意数量的产品,而不仅仅是 2 个。

【讨论】:

  • 啊,好吧,我应该告诉
  • 我应该告诉你,我当然不会在我的表单中使用硬编码值。所有 id 值和产品相关信息都是动态 php 输出。所以是的,它当然是由 foreach 生成的。表单永远不会发送 $_POST,因为使用 jquery 会阻止默认提交按钮;所以我实际上可以做 jquery ajax 的东西。我已经有一个 api 正在使用 $_POST 到购物车页面而没有 ajax 正是这种形式。需要股票信息。否则,客户可能会在他们的购物车中添加超过可用库存。
  • 我理解给出的 HTML 表单是 PHP 代码的输出。关于“库存”,我的意思是我认为您不需要将该值发送回服务器。不是只读的吗? jQuery 的 .serialize() 将仅包含具有 name 属性的输入元素的值,因此如果您在输入元素上省略 name 属性,则输入元素不会包含在 .serialize() 的输出中。
猜你喜欢
  • 2021-04-04
  • 1970-01-01
  • 1970-01-01
  • 2015-12-04
  • 1970-01-01
  • 2019-10-02
  • 1970-01-01
  • 2014-11-21
  • 1970-01-01
相关资源
最近更新 更多