WooCommerce - 数量变化时自动更新总价
Posted
技术标签:
【中文标题】WooCommerce - 数量变化时自动更新总价【英文标题】:WooCommerce - auto update total price when quantity changed 【发布时间】:2014-11-26 01:05:03 【问题描述】:我已经搜索了几天,但我还没有答案。基本上,我正在尝试用 ajax 调用替换 woocommerce 标准“更新购物车”按钮,当数量发生变化时,它会自动更新订单总价。 这是我的html
<div class="cart_item">
<div class="product-thumbnail">
<a href="http://example.com"><img 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 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>
在functions.php中我有一个更新总数的函数:
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;
而Jquery代码是:
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;
);
);
如果购物车中只有一件产品,上面的代码效果很好。
但是当我添加一些其他产品并更改其中一个产品的数量时,我的功能会使用我所有产品的最后一个数量值。
例如,第二张图片的总价必须是 7000(2000*1+2500*2) 但它是 9000(2000*2+2500*2)。 我是 ajax 和 jquery 新手,非常感谢任何帮助。
【问题讨论】:
【参考方案1】:这是因为您要更新所有购物车,而不仅仅是一个产品。
首先,您需要在 javascript 脚本上发送商品购物车哈希(它不是安全哈希,而是包含所有产品变体的产品哈希):
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
;
然后你可以编辑你的function update_total_price
,我已经简化了;)
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;
【讨论】:
这里缺少的是,rf_cart_params
是如何设置的..?如果我调用上面的 jQuery 函数,我会得到一个ReferenceError: rf_cart_params is not defined
。也许原因是,我什至没有加载购物车页面,我在产品存档页面上显示了购物车(实际上我检查了它,当我尝试原始购物车页面上的代码时,它是同样的问题.. )。那么如何让脚本加载/变量集..?
实际上我现在在购物车页面上找到了该对象,但其名称为wc_cart_params
。将尝试在我的存档页面上对这些内容进行排队..【参考方案2】:
这是实现此目的的更简单方法。所有功劳归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
【讨论】:
这个答案与这个问题没有任何关系。虽然它可能会正确计算价格,但此工具仅用于计算产品页面上的价格,而问题是关于购物车页面。当您在购物车页面上更改数量并且不将其提交给 wc 时,价格可能会发生变化,但购物车不会。 @honk31 你是对的!没注意到。我想它仍然值得保留在这里,因为它可能会在未来帮助某人【参考方案3】:自 2016 年 6 月发布的 WooCommerce 2.6.0 以来,WooCommerce 购物车页面在单击更新购物车按钮后使用 Ajax 更新购物车总数。 WooCommerce 2.6.0 需要 WP 4.4 或更高版本。
无需担心后端和创建自己的 Ajax 调用,可以使用分配给更新购物车按钮的那个。
要立即使用此功能,您可以使用我的免费插件,它还有一些方便的附加选项:
Ajax Cart AutoUpdate for WooCommerce
或使用子主题执行以下操作。隐藏更新购物车按钮,然后将脚本加入队列,该脚本会在购物车页面数量更改时触发默认更新购物车事件(适用于购物车和迷你购物车小部件)。使用模板重定向钩子,依赖 jQuery 并确保此脚本仅在购物车页面上加载。
要使用 CSS 隐藏按钮,请使用类 .button 而不是标签,以使其与所有 WooCommerce 版本兼容:
.button[name='update_cart']
display: none!important;
或者隐藏带有 PHP 头部样式的按钮:
add_action('wp_head', 'hide_update_cart_button', 20);
function hide_update_cart_button()
echo "<style>.button[name='update_cart'] display: none!important;</style>";
使用 jQuery 将脚本排入队列:
add_action( 'template_redirect', 'auto_update_cart_totals' );
function auto_update_cart_totals()
if (! is_cart() ) return; // Only if it's cart page.
// Enqueue js file.
add_action( 'wp_enqueue_scripts', 'my_cart_autoupdate' );
function my_cart_autoupdate( )
// Here goes code to hide CSS button if you decide to use PHP solution for styling.
wp_enqueue_script( 'my-cart-autoupdate', 'path-to-js-file-its-name-and-extension', array('jquery'), '', true);
关于 jQuery 代码最重要且通常被忽略的事情是设置更新延迟,在本例中为 1000,我的插件允许在设置中更改此值。如果用户在此延迟期间再次更改数量,它将重置为完整持续时间。如果它没有实现并且你通过单击增量按钮将数量从 1 更改为 10,它将触发 9 个 Ajax 调用而不是 1 个。将其放在 .js 文件中:
var timeout;
jQuery('div.woocommerce').on('change keyup mouseup', 'input.qty', function() // keyup and mouseup for Firefox support
if (timeout != undefined) clearTimeout(timeout); //cancel previously scheduled event
if (jQuery(this).val() == '') return; //qty empty, instead of removing item from cart, do nothing
timeout = setTimeout(function()
jQuery('[name="update_cart"]').trigger('click');
, 1000 );
);
【讨论】:
以上是关于WooCommerce - 数量变化时自动更新总价的主要内容,如果未能解决你的问题,请参考以下文章