WooCommerce - auto update total price when quantity changed
Solution 1
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;
}
Solution 2
Here's a simpler way of achieving this. All credit goes to Reigel Gallarde.
// we are going to hook this on priority 31, so that it would display below add to cart button.
add_action( 'woocommerce_single_product_summary', 'woocommerce_total_product_price', 31 );
function woocommerce_total_product_price() {
global $woocommerce, $product;
// let's setup our divs
echo sprintf('<div id="product_total_price" style="margin-bottom:20px;display:none">%s %s</div>',__('Product Total:','woocommerce'),'<span class="price">'.$product->get_price().'</span>');
echo sprintf('<div id="cart_total_price" style="margin-bottom:20px;display:none">%s %s</div>',__('Cart Total:','woocommerce'),'<span class="price">'.$product->get_price().'</span>');
?>
<script>
jQuery(function($){
var price = <?php echo $product->get_price(); ?>,
current_cart_total = <?php echo $woocommerce->cart->cart_contents_total; ?>,
currency = '<?php echo get_woocommerce_currency_symbol(); ?>';
$('[name=quantity]').change(function(){
if (!(this.value < 1)) {
var product_total = parseFloat(price * this.value),
cart_total = parseFloat(product_total + current_cart_total);
$('#product_total_price .price').html( currency + product_total.toFixed(2));
$('#cart_total_price .price').html( currency + cart_total.toFixed(2));
}
$('#product_total_price,#cart_total_price').toggle(!(this.value <= 1));
});
});
</script>
<?php
}
grimasa
Updated on May 14, 2020Comments
-
grimasa almost 4 years
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">×</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">×</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.
-
honk31 about 8 yearswhat is missing here is, how does the
rf_cart_params
gets set..? if i call the above jQuery function, i get aReferenceError: rf_cart_params is not defined
. maybe the cause is, that i didn't even load the cart page, i show the cart on the products-archive page (actually i checked it, when i try out the code on the original cart page, its the same issue..). so how do i get the scripts loaded / variables set..? -
honk31 about 8 yearsactually on the cart page i now found the object, but its called
wc_cart_params
. will try to enque those on my archive page.. -
honk31 about 8 yearsthis answer has not really to do anything with the question. while it might calculate the price properly, this tool is only to calculate the price on the prodcut page, while the question is regarding the cart page. when you change quantity on the cart page and don't submit this to wc, the price might change, but the cart won't.
-
adamj about 8 years@honk31 you're right! hadn't noticed. I guess it's still worth keeping it here because it might help someone in the future