WooCommerce默认无法一次添加多个产品到购物车,这需要写程序或装插件实现。插件有Multiple Products to Cart等。本文介绍代码的方法,去除复杂的修饰,只看原理。
一次添加多个产品就是把添加一个产品的过程重复多次
WooCommerce内置的添加购物车的函数如下所示,我们要做的就是把这个函数调用好几遍,直到把产品加完为止。
WC()->cart->add_to_cart( $product_id = 0, $quantity = 1, $variation_id = 0, $variation = array(), $cart_item_data = array() );
添加一个产品的过程并不简单,要从头到脚的验证这个产品,比如库存还够不够,产品有没有特殊售卖规则,是什么类型的产品、是否处于可销售状态。通过了复杂的检查后,就会为产品生成一个$cart_item_key
,并将这个key添加到购物车里,简单描述就是下面这样:
// array里存放该产品的所有信息
WC()->cart->cart_contents[$cart_item_key] = array(...)
这还没完,产品加进去了还要算一下总价,比如运费、税费、额外费用等等,这里会有个问题,我们最后讲。
加购物车的过程很复杂,但你也只能耐着性子一个一个的加,因为woocommerce有很多产品规则,不可能让你多线程去操作购物车,万一产生时间竞争问题,最后结果是啥就不可控了。
下面是一次添加多个产品的函数:
function add_multiple_products_to_cart( $products ){
if( is_array($products) && sizeof($products) ){
// 在全部产品添加完之前不要计算总价(包括产品总价、运费、额外费用、税费等)
remove_action( 'woocommerce_add_to_cart', array( WC()->cart, 'calculate_totals' ), 20, 0 );
foreach( $products as $product_to_add ){
if ( ! isset( $product_to_add['product_id'] ) ) {
continue;
}
// 获取产品ID、数量等信息
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $product_to_add['product_id'] ) );
$product = wc_get_product( $product_id );
$quantity = empty( $product_to_add['quantity'] ) ? 1 : wc_stock_amount( wp_unslash( $product_to_add['quantity'] ) );
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity );
$product_status = get_post_status( $product_id );
$variation_id = 0;
$variation = array();
// 如果是variation,需要获取他的父级产品信息
if ( $product && 'variation' === $product->get_type() ) {
$variation_id = $product_id;
$product_id = $product->get_parent_id();
$variation = $product->get_variation_attributes();
}
// 调用woocommerce的内置函数将产品添加到购物车里
$cart_item_key = WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation);
// 简单先试一下结果,如果用在ajax里,应该用wp_json_send()函数返回结果。
$added_product_id = $variation_id ? $variation_id : $product_id;
if ( $passed_validation && false !== $cart_item_key && 'publish' === $product_status ) {
wc_add_notice( '成功添加了产品 - ' .$added_product_id );
} else {
wc_add_notice( '产品添加失败 - ' . $added_product_id, 'error' );
}
}
// 现在可以计算总价了
WC()->cart->calculate_totals();
}
}
简单测试的话,找个测试站点,在主题的functions.php
里写点代码就行,每次刷新页面都会执行。如果要加一个variation产品,则product_id
应填写variation_id
。
add_action( 'template_redirect', function(){
$products = array(
array(
'product_id' => 801,
'quantity' => 10,
),
array(
'product_id' => 802,
'quantity' => 10,
)
);
add_multiple_products_to_cart($products);
});
计算总价会影响加购物的速度
每加一个产品都会计算总价,这对原始逻辑不是问题。但假设我们做一个可以一次添加几十个产品的界面,如果加一个产品要话1s,那加20个就是20s的时间,有点恐怖。
有的网站会出现添加购物车极慢的情况,可能是数据量太大,用了太多的variations、或者服务器性能不好,但不要忽略这个计算总价的问题。
什么情况下计算总价会影响加购物车的速度呢?运费和税费有时会很复杂,可能要从第三方网站直接查询结果。添加购物车时缓存是无效的,那么去其它站点查询这个速度就不能忽略了,毕竟访问网站再快也会花掉几百毫秒,一次添加多个产品时这个时间会很影响速度。
所以代码中通过remove_action( 'woocommerce_add_to_cart', array( WC()->cart, 'calculate_totals' ), 20, 0 );
禁止计算总价,待产品全部加完了再计算,这样不管加多少产品,都只会计算一次总价。
不知道是不是最近WooCommerce的更新还是一直都有,我发现
WC()->cart->add_to_cart() 和 WC()->cart->remove_cart_item() 以及WC()->cart->set_quantity() 这些执行完毕后
即使不调用方法
WC()->cart->calculate_totals()
重新查询总价依旧会刷新的
但是
WC()->cart->remove_coupons()和WC()->cart->apply_coupons() 这俩运行后还是需要calculate_totals,要不然总价不会变
你说的没错,更改购物车的产品、产品数量就会触发价格计算,这个一直都有。但有些带优惠的产品,通过程序加到购物车里,mini cart里的价格会不带优惠,需要调用calculate_totals。