调用结算页通过URL添加多商品前,WooCommerce购物车清空失败
问题:WooCommerce中调用
WC()->cart->empty_cart()无法清空购物车的原因及解决办法 我通过以下代码实现了通过URL(格式如...com/checkout/?add-to-cart=632:11,422:7)直接跳转到结算页并添加多个商品,但调用WC()->cart->empty_cart();时,无论用户是否登录,都无法清空购物车,请问这是什么原因?
// 允许通过如下格式的URL向结算页或购物车添加多商品 ...com/checkout/?add-to-cart=632:11,422:7 function add_multiple_products_to_cart_9R_M2asdf() { // 确保已安装WooCommerce,且存在格式正确的'add-to-cart'查询参数。 if ( ! class_exists( 'WC_Form_Handler' ) || empty( $_REQUEST['add-to-cart'] ) || false === strpos( $_REQUEST['add-to-cart'], ',' ) ) { return; } // 添加新商品前清空购物车,否则会追加到已有商品中... WC()->cart->empty_cart(); // 移除WooCommerce默认的add_to_cart_action钩子。 remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 ); // 拆分商品ID和数量。 $product_entries = explode( ',', sanitize_text_field( $_REQUEST['add-to-cart'] ) ); foreach ( $product_entries as $entry ) { // 将每个条目拆分为商品ID和数量。 list($product_id, $quantity) = array_map('absint', explode( ':', $entry ) + [null, 1]); if ( ! $product_id ) { continue; } // 在请求中设置数量。 $_REQUEST['quantity'] = $quantity; // 使用WooCommerce默认方法处理最后一个商品。 if ( end($product_entries) === $entry ) { $_REQUEST['add-to-cart'] = $product_id; return WC_Form_Handler::add_to_cart_action(); } // 处理商品。 $product_id = apply_filters( 'woocommerce_add_to_cart_product_id', $product_id ); $product = wc_get_product( $product_id ); if ( ! $product ) { continue; } $add_to_cart_handler = apply_filters( 'woocommerce_add_to_cart_handler', $product->get_type(), $product ); // 处理不同类型的商品。 if ( 'variable' === $add_to_cart_handler ) { // 可变商品 woo_invoke_private_method_93gK_M3q( 'WC_Form_Handler', 'add_to_cart_handler_variable', $product_id ); } elseif ( 'grouped' === $add_to_cart_handler ) { // 分组商品 woo_invoke_private_method_93gK_M3q( 'WC_Form_Handler', 'add_to_cart_handler_grouped', $product_id ); } elseif ( has_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler ) ) { // 自定义处理器 do_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler ); } else { // 简单商品 woo_invoke_private_method_93gK_M3q( 'WC_Form_Handler', 'add_to_cart_handler_simple', $product_id ); } } } add_action( 'wp_loaded', 'add_multiple_products_to_cart_9R_M2asdf', 15 ); /** * 调用类的私有方法。 * * @param string $class_name * @param string $method_name * @param mixed ...$args * @return mixed */ function woo_invoke_private_method_93gK_M3q( $class_name, $method_name, ...$args ) { if ( version_compare( phpversion(), '5.3', '<' ) ) { throw new Exception( 'PHP版本不支持ReflectionClass::setAccessible()', __LINE__ ); } $reflection = new ReflectionClass( $class_name ); $method = $reflection->getMethod( $method_name ); $method->setAccessible( true ); return $method->invoke( null, ...$args ); }
原因分析
- 钩子执行时机冲突:当前函数挂载在
wp_loaded钩子(优先级15),但WooCommerce会在woocommerce_init或更早阶段从session/cookie恢复购物车数据,导致清空操作后旧数据又被重新加载。 - session/cookie未同步更新:
empty_cart()仅清空了内存中的购物车对象,未主动更新存储用户购物车数据的session(登录用户)或cookie(未登录用户),页面加载后旧数据会被再次读取。 - 默认方法的逻辑干扰:处理最后一个商品时调用的
WC_Form_Handler::add_to_cart_action()内部包含购物车初始化逻辑,会覆盖之前的清空操作。
解决办法
1. 调整钩子执行时机
将函数挂载到更早的woocommerce_init钩子,确保在WooCommerce恢复购物车前执行清空操作:
add_action( 'woocommerce_init', 'add_multiple_products_to_cart_9R_M2asdf', 10 );
2. 清空后强制同步session/cookie
在empty_cart()后手动更新session和cookie,确保存储的购物车数据被清空:
WC()->cart->empty_cart(); // 更新session中的购物车数据 WC()->session->set( 'cart', WC()->cart->get_cart() ); // 未登录用户更新购物车hash cookie if ( ! is_user_logged_in() ) { wc_setcookie( 'woocommerce_cart_hash', WC()->cart->get_cart_hash() ); }
3. 统一商品处理逻辑
移除对默认add_to_cart_action()的调用,沿用私有方法处理最后一个商品,避免逻辑冲突:
// 替换原最后一个商品的处理代码 // if ( end($product_entries) === $entry ) { // $_REQUEST['add-to-cart'] = $product_id; // return WC_Form_Handler::add_to_cart_action(); // } // 改为和其他商品一致的处理逻辑 $add_to_cart_handler = apply_filters( 'woocommerce_add_to_cart_handler', $product->get_type(), $product ); if ( 'variable' === $add_to_cart_handler ) { woo_invoke_private_method_93gK_M3q( 'WC_Form_Handler', 'add_to_cart_handler_variable', $product_id ); } elseif ( 'grouped' === $add_to_cart_handler ) { woo_invoke_private_method_93gK_M3q( 'WC_Form_Handler', 'add_to_cart_handler_grouped', $product_id ); } elseif ( has_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler ) ) { do_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler ); } else { woo_invoke_private_method_93gK_M3q( 'WC_Form_Handler', 'add_to_cart_handler_simple', $product_id ); }
4. 确保钩子移除生效
将移除默认add_to_cart_action钩子的代码移到清空购物车之前,避免默认逻辑干扰:
// 先移除默认钩子 remove_action( 'wp_loaded', array( 'WC_Form_Handler', 'add_to_cart_action' ), 20 ); // 再清空购物车 WC()->cart->empty_cart();
内容的提问来源于stack exchange,提问作者eva last
相关产品推荐
相关产品推荐

