WooCommerce - 数量变化时自动更新总价

2021-12-22 00:00:00 jquery php wordpress woocommerce

我已经找了好几天了,但还没有答案.基本上,我试图用 ajax 调用替换 woocommerce 标准的更新购物车"按钮,当数量发生变化时,它会自动更新订单总价.这是我的html

<div class="product-thumbnail"><a href="http://example.com"><img width="90" height="90" src="缩略图路径"/></a>

<div class="product-name"><a class="cart-page-product__title" href="http://example.com">Product1 name</a>

<div class="product-quantity"><div class="数量"><input type="number" step="1" name="cart[some_security_key][qty]" value="1" class="input-text qty text" size="4"/>

<div class="product-subtotal"><span class="amount">2 000</span></div><div class="product-remove"><a class="product-remove_link" href="http://example.com/?remove_item">&times;</a>

<div class="cart_item"><div class="product-thumbnail"><a href="http://example.com"><img width="90" height="90" src="缩略图路径"/></a>

<div class="product-name"><a class="cart-page-product__title" href="http://example.com">Product2 name</a>

<div class="product-quantity"><div class="数量"><input type="number" step="1" name="cart[some_security_key][qty]" value="1" class="input-text qty text" size="4"/>

<div class="product-subtotal"><span class="amount">2 000</span></div><div class="product-remove"><a class="product-remove_link" href="http://example.com/?remove_item">&times;</a>

在functions.php中,我有一个更新总数的函数:

公共函数update_total_price() {check_ajax_referer('update_total_price', 'security');如果(!定义('WOOCOMMERCE_CART')){定义('WOOCOMMERCE_CART',真);}$cart_updated = false;$cart_totals = isset( $_POST['cart'] ) ?$_POST['购物车'] : '';如果(大小(WC()->购物车->get_cart())> 0){foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {$_product = $values['data'];//如果没有发布更新的数量,则跳过产品如果(!isset($_POST['数量'])){//if ( !isset( $cart_totals[ $cart_item_key ]['qty'] ) ) {继续;}//消毒$quantity = apply_filters('woocommerce_stock_amount_cart_item', apply_filters('woocommerce_stock_amount', preg_replace("/[^0-9.]/", '', filter_var($_POST['quantity'], FILTER_SANITIZE_NUMBER_INT)_item), $);//$quantity = apply_filters( 'woocommerce_stock_amount_cart_item', apply_filters( 'woocommerce_stock_amount', preg_replace( "/[^0-9.]/", '', $cart_totals[ $cart_item_key ]['qty'] ) ), $购物车项键 );if ( '' === $quantity || $quantity == $values['quantity'] )继续;//更新购物车验证$passed_validation = apply_filters('woocommerce_update_cart_validation', true, $cart_item_key, $values, $quantity );//is_sold_individually如果 ( $_product->is_sold_individually() && $quantity > 1 ) {wc_add_notice( sprintf( __( '您的购物车中只能有 1 %s.', 'woocommerce' ), $_product->get_title() ), 'error' );$passed_validation = false;}如果($passed_validation){WC()->cart->set_quantity( $cart_item_key, $quantity, false );}$cart_updated = true;}}//触发操作 - 让第 3 方在需要时更新购物车并更新 $cart_updated 变量$cart_updated = apply_filters( 'woocommerce_update_cart_action_cart_updated', $cart_updated );如果( $cart_updated ){//重新计算我们的总数WC()->购物车->calculate_totals();woocommerce_cart_totals();出口;}}

而 Jquery 代码是:

jQuery( 函数( $ ) {//wc_cart_params 需要继续,确保对象存在if ( typeof wc_cart_params === '未定义' ) {返回假;}//购物车价格更新取决于数量//$( document ).on( 'click', '.quantity', function() {$( document ).on( 'change', '.quantity, input[type=number]', function() {var qty = $( this ).val();var currentVal = parseFloat(数量);$( 'div.cart_totals' ).block({ message: null, overlayCSS: { background: '#fff url(' + wc_cart_params.ajax_loader_url + ') 无重复中心', backgroundSize: '16px 16px', opacity: 0.6} });变量数据 = {动作:'rf_update_total_price',安全性:rf_cart_params.rf_update_total_price_nonce,数量:currentVal};$.post( rf_cart_params.ajax_url, 数据, 函数( 响应) {$( 'div.cart_totals' ).replaceWith( response );$('body').trigger('rf_update_total_price');});返回假;});});

如果购物车中只有一种产品,则上述代码效果很好.

但是当我添加一些其他产品并更改其中一个产品的数量时,我的函数会使用我所有产品的最后一个数量值.

例如,第二张图片的总价必须是 7000(2000*1+2500*2) 但它是 9000(2000*2+2500*2).我是 ajax 和 jquery 的新手,所以感谢您的帮助.

解决方案

这是因为您要更新所有购物车,而不仅仅是产品.

首先,您需要在 javascript 脚本中发送商品购物车哈希(它不是安全哈希,而是包含所有产品变体的产品哈希):

var item_hash = $( this ).attr( 'name' ).replace(/cart[([w]+)][qty]/g, "$1");变量数据 = {动作:'rf_update_total_price',安全性:rf_cart_params.rf_update_total_price_nonce,数量:currentVal,哈希:item_hash};

然后你可以编辑你的函数update_total_price,我已经简化了;)

function update_total_price() {//如果 WC_Cart 上没有发布更新数量或没有哈希值,则跳过产品if( !isset( $_POST['hash'] ) || !isset( $_POST['quantity'] ) ){出口;}$cart_item_key = $_POST['hash'];if(!isset(WC()->cart->get_cart()[$cart_item_key])){出口;}$values = WC()->cart->get_cart()[ $cart_item_key ];$_product = $values['data'];//消毒$quantity = apply_filters('woocommerce_stock_amount_cart_item', apply_filters('woocommerce_stock_amount', preg_replace("/[^0-9.]/", '', filter_var($_POST['quantity'], FILTER_SANITIZE_NUMBER_INT)_item), $);if ( '' === $quantity || $quantity == $values['quantity'] )出口;//更新购物车验证$passed_validation = apply_filters('woocommerce_update_cart_validation', true, $cart_item_key, $values, $quantity );//is_sold_individually如果 ( $_product->is_sold_individually() && $quantity > 1 ) {wc_add_notice( sprintf( __( '您的购物车中只能有 1 %s.', 'woocommerce' ), $_product->get_title() ), 'error' );$passed_validation = false;}如果($passed_validation){WC()->cart->set_quantity( $cart_item_key, $quantity, false );}//重新计算我们的总数WC()->购物车->calculate_totals();woocommerce_cart_totals();出口;}

I've been searching for several days but I have no answer yet. Basically, I'm trying to replace woocommerce standart "update cart" button with ajax call, which automatically updates order total price when quantity changed. This is my html

<div class="cart_item">
    <div class="product-thumbnail">
        <a href="http://example.com"><img width="90" height="90" src="path to thumbnail"/></a>
    </div>

    <div class="product-name">
        <a class="cart-page-product__title" href="http://example.com">Product1 name</a>
    </div>

    <div class="product-quantity">
        <div class="quantity">
            <input type="number" step="1"   name="cart[some_security_key][qty]" value="1" class="input-text qty text" size="4"/>
        </div>
    </div>

    <div class="product-subtotal"><span class="amount">2 000</span></div>
        <div class="product-remove">
            <a class="product-remove_link" href="http://example.com/?remove_item">&times;</a>
        </div>
</div>
<div class="cart_item">
    <div class="product-thumbnail">
        <a href="http://example.com"><img width="90" height="90" src="path to thumbnail"/></a>
    </div>

    <div class="product-name">
        <a class="cart-page-product__title" href="http://example.com">Product2 name</a>
    </div>

    <div class="product-quantity">
        <div class="quantity">
            <input type="number" step="1"   name="cart[some_security_key][qty]" value="1" class="input-text qty text" size="4"/>
        </div>
    </div>

    <div class="product-subtotal"><span class="amount">2 000</span></div>
        <div class="product-remove">
            <a class="product-remove_link" href="http://example.com/?remove_item">&times;</a>
        </div>
</div>

In functions.php I have a function for updating totals:

public function update_total_price() {
        check_ajax_referer( 'update_total_price', 'security' );

        if ( ! defined('WOOCOMMERCE_CART') ) {
            define( 'WOOCOMMERCE_CART', true );
        }

        $cart_updated = false;
            $cart_totals  = isset( $_POST['cart'] ) ? $_POST['cart'] : '';

            if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
                foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
                    $_product = $values['data'];

                    // Skip product if no updated quantity was posted
                    if ( ! isset( $_POST['quantity'] ) ) {
                    // if ( ! isset( $cart_totals[ $cart_item_key ]['qty'] ) ) {
                        continue;
                    }

                    // Sanitize
                    $quantity = apply_filters( 'woocommerce_stock_amount_cart_item', apply_filters( 'woocommerce_stock_amount', preg_replace( "/[^0-9.]/", '', filter_var($_POST['quantity'], FILTER_SANITIZE_NUMBER_INT)) ), $cart_item_key );
                    // $quantity = apply_filters( 'woocommerce_stock_amount_cart_item', apply_filters( 'woocommerce_stock_amount', preg_replace( "/[^0-9.]/", '', $cart_totals[ $cart_item_key ]['qty'] ) ), $cart_item_key );

                    if ( '' === $quantity || $quantity == $values['quantity'] )
                        continue;

                    // Update cart validation
                    $passed_validation  = apply_filters( 'woocommerce_update_cart_validation', true, $cart_item_key, $values, $quantity );

                    // is_sold_individually
                    if ( $_product->is_sold_individually() && $quantity > 1 ) {
                        wc_add_notice( sprintf( __( 'You can only have 1 %s in your cart.', 'woocommerce' ), $_product->get_title() ), 'error' );
                        $passed_validation = false;
                    }

                    if ( $passed_validation ) {
                        WC()->cart->set_quantity( $cart_item_key, $quantity, false );
                    }

                    $cart_updated = true;
                }
            }

            // Trigger action - let 3rd parties update the cart if they need to and update the $cart_updated variable
            $cart_updated = apply_filters( 'woocommerce_update_cart_action_cart_updated', $cart_updated );

            if ( $cart_updated ) {
                // Recalc our totals
                WC()->cart->calculate_totals();
                woocommerce_cart_totals();
                exit;
            }

    }

And Jquery code is:

jQuery( function( $ ) {

    // wc_cart_params is required to continue, ensure the object exists
    if ( typeof wc_cart_params === 'undefined' ) {
        return false;
    }

    // Cart price update depends on quantity
    //$( document ).on( 'click', '.quantity', function() {


    $( document ).on( 'change', '.quantity, input[type=number]', function() {
        var qty = $( this ).val();
        var currentVal  = parseFloat( qty);

        $( 'div.cart_totals' ).block({ message: null, overlayCSS: { background: '#fff url(' + wc_cart_params.ajax_loader_url + ') no-repeat center', backgroundSize: '16px 16px', opacity: 0.6 } });

        var data = {
            action: 'rf_update_total_price',
            security: rf_cart_params.rf_update_total_price_nonce,
            quantity: currentVal
        };

        $.post( rf_cart_params.ajax_url, data, function( response ) {

            $( 'div.cart_totals' ).replaceWith( response );
            $( 'body' ).trigger( 'rf_update_total_price' );

        });
        return false;
    });
});

The above code works great if only one product is in the cart.

But when I add some other product and change quantity of one of them my function use last value of quantity for all of my products.

For example, total price for the second image must be 7000(2000*1+2500*2) but it is 9000(2000*2+2500*2). I am new to ajax and jquery so appreciate any help.

解决方案

It's because you are updating all your cart, not just a product.

First you need to send the item cart hash (it's not a security hash, but the product hash with all the product variation) on the javascript script:

var item_hash = $( this ).attr( 'name' ).replace(/cart[([w]+)][qty]/g, "$1");
var data = {
        action: 'rf_update_total_price',
        security: rf_cart_params.rf_update_total_price_nonce,
        quantity: currentVal,
        hash : item_hash 
    };

Then you can edit your function update_total_price, I've simplified ;)

function update_total_price() {

    // Skip product if no updated quantity was posted or no hash on WC_Cart
    if( !isset( $_POST['hash'] ) || !isset( $_POST['quantity'] ) ){
        exit;
    }

    $cart_item_key = $_POST['hash'];

    if( !isset( WC()->cart->get_cart()[ $cart_item_key ] ) ){
        exit;
    }

    $values = WC()->cart->get_cart()[ $cart_item_key ];

    $_product = $values['data'];

    // Sanitize
    $quantity = apply_filters( 'woocommerce_stock_amount_cart_item', apply_filters( 'woocommerce_stock_amount', preg_replace( "/[^0-9.]/", '', filter_var($_POST['quantity'], FILTER_SANITIZE_NUMBER_INT)) ), $cart_item_key );

    if ( '' === $quantity || $quantity == $values['quantity'] )
        exit;

    // Update cart validation
    $passed_validation  = apply_filters( 'woocommerce_update_cart_validation', true, $cart_item_key, $values, $quantity );

    // is_sold_individually
    if ( $_product->is_sold_individually() && $quantity > 1 ) {
        wc_add_notice( sprintf( __( 'You can only have 1 %s in your cart.', 'woocommerce' ), $_product->get_title() ), 'error' );
        $passed_validation = false;
    }

    if ( $passed_validation ) {
        WC()->cart->set_quantity( $cart_item_key, $quantity, false );
    }

    // Recalc our totals
    WC()->cart->calculate_totals();
    woocommerce_cart_totals();
    exit;
}

相关文章