OStack程序员社区-中国程序员成长平台

标题: php - WooCommerce - auto update total price when quantity changed [打印本页]

作者: 菜鸟教程小白    时间: 2022-6-22 22:05
标题: php - WooCommerce - auto update total price when quantity changed

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">roduct1 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">roduct2 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. enter image description here

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.

enter image description here

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.



Best Answer-推荐答案


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;
}





欢迎光临 OStack程序员社区-中国程序员成长平台 (https://ostack.cn/) Powered by Discuz! X3.4