WooCommerce AJAX加购后cart fragments未更新问题排查
原有实现代码
商品页购物车总额展示模板
<p>Your total: <span class="r_cart_total"><?= WC()->cart->get_cart_total(); ?></span></p>
无刷新更新片段挂载代码
add_filter( 'woocommerce_add_to_cart_fragments', 'wc_refresh_cart_fragments', 50, 1 ); function wc_refresh_cart_fragments( $fragments ){ $cart_count = WC()->cart->get_cart_contents_count(); $cart_total = WC()->cart->get_cart_total(); // Normal version $count_normal = '<span class="r_cart_total">' . $cart_total . '</span>'; $fragments['.r_cart_total'] = $count_normal; return $fragments; }
自定义AJAX加购代码
/** * Add to cart product using ajax **/ add_action('wp_ajax_woocommerce_ajax_add_to_cart', 'woocommerce_ajax_add_to_cart'); add_action('wp_ajax_nopriv_woocommerce_ajax_add_to_cart', 'woocommerce_ajax_add_to_cart'); function woocommerce_ajax_add_to_cart() { $product_id = apply_filters('woocommerce_add_to_cart_product_id', absint($_POST['product_id'])); $quantity = empty($_POST['quantity']) ? 1 : wc_stock_amount($_POST['quantity']); $variation_id = absint($_POST['variation_id']); $passed_validation = apply_filters('woocommerce_add_to_cart_validation', true, $product_id, $quantity); $product_status = get_post_status($product_id); $is_buy_all = filter_var($_POST['is_buy_all'], FILTER_VALIDATE_BOOLEAN); //if buy all product then remove all other products in the cart if($is_buy_all){ foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { WC()->cart->remove_cart_item( $cart_item_key ); } } if ($passed_validation && WC()->cart->add_to_cart($product_id, $quantity, $variation_id) && 'publish' === $product_status) { do_action('woocommerce_ajax_added_to_cart', $product_id); //show success message add to cart if ('yes' === get_option('woocommerce_cart_redirect_after_add')) { wc_add_to_cart_message(array($product_id => $quantity), true); } if($is_buy_all && !empty($_POST['sub_products'])){ $sub_products = json_decode(stripslashes($_POST['sub_products'])); foreach($sub_products as $sub_product){ $sub_product = trim($sub_product); $sub_product_id = apply_filters('woocommerce_add_to_cart_product_id', absint($sub_product)); $quantity = 1; $variation_id = absint($variation_id); $passed_validation = apply_filters('woocommerce_add_to_cart_validation', true, $sub_product_id, $quantity); $sub_product_status = get_post_status($sub_product_id); if($passed_validation && WC()->cart->add_to_cart($sub_product_id, $quantity) && 'publish' === $sub_product_status) { do_action('woocommerce_ajax_added_to_cart', $sub_product_id); } } } WC_AJAX :: get_refreshed_fragments(); wp_die(); } else { $data = array( 'error' => true, 'product_url' => apply_filters('woocommerce_cart_redirect_after_error', get_permalink($product_id), $product_id)); echo wp_send_json($data); wp_die(); } }
故障现象
移除购物车商品时,总额片段可正常无刷新更新;添加商品到购物车时,虽然已经在加购逻辑末尾调用WC_AJAX::get_refreshed_fragments(),但总额片段无法正常更新。
故障原因
- 核心问题是购物车总额计算时机错误:WooCommerce的
WC_Cart::add_to_cart()方法为了优化性能,不会在每次加购操作后立即重新计算购物车总额,尤其是代码中存在连续加购主商品、批量加购子商品的场景,购物车totals数据处于缓存状态,此时直接调用片段刷新方法,过滤器中拿到的get_cart_total()是加购操作前的旧值,前端替换后和更新前数值一致,表现为fragments不刷新。 - 移除商品时功能正常的原因是
WC_Cart::remove_cart_item()方法内部会自动触发购物车总额重算,所以移除场景下能拿到最新值。 - 额外问题:直接输出
get_cart_total()的原始值,没有经过WooCommerce价格格式化,返回的内容不带货币符号、千位分隔符,和全站价格显示规则不一致;WC_AJAX :: get_refreshed_fragments()的类名和方法中间多了空格,存在语法兼容风险;get_refreshed_fragments()方法本身会输出JSON后自动终止程序,后面多余的wp_die()属于无效代码。
修复步骤
- 所有购物车增删操作完成后,手动触发购物车总额重算,再调用fragments刷新方法
- 优化fragments返回的价格内容,使用原生
wc_price()方法格式化输出,保持价格显示规则一致 - 修正代码语法问题,移除多余空格和无效终止逻辑
- 确保前端自定义AJAX逻辑没有覆盖WooCommerce原生的fragments替换机制,后端返回的片段数据由WooCommerce前端脚本自动完成DOM替换即可,不需要额外写JS修改节点内容。
修复后代码
1. 购物车总额片段过滤器代码
add_filter( 'woocommerce_add_to_cart_fragments', 'wc_refresh_cart_fragments', 50, 1 ); function wc_refresh_cart_fragments( $fragments ){ // 强制重算购物车数据,避免读取缓存旧值 WC()->cart->calculate_totals(); // 格式化价格,匹配全站价格显示规则 $cart_total_html = wc_price( WC()->cart->get_total() ); $fragments['.r_cart_total'] = '<span class="r_cart_total">' . $cart_total_html . '</span>'; return $fragments; }
2. 自定义AJAX加购成功分支修改
找到自定义加购方法中加完所有商品(主商品+子商品)后的代码段,替换为以下内容:
// 所有增删购物车操作完成后,强制重算购物车总额 WC()->cart->calculate_totals(); // 输出刷新后的fragments,方法内部会自动终止程序 WC_AJAX::get_refreshed_fragments();
内容的提问来源于stack exchange,提问作者milind prajapati
相关产品推荐
相关产品推荐

