You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

仅更新WooCommerce购物车/结账页面小计的正确Hook咨询

解决WooCommerce中只想修改小计而非产品价格的问题

嘿,我明白你的需求了——你现在的代码会直接修改产品本身的价格,但你希望保持产品价格显示不变,只把自定义字段的金额加到小计里对吧?之前尝试woocommerce_cart_product_subtotal没用,是因为这个钩子只负责修改显示的文本,不会影响实际的订单金额计算,所以必须同时处理显示和实际金额逻辑两部分才行。

问题分析

你原来的代码是通过set_price()修改了产品的基础价格,这会导致购物车中显示的产品价格变成「原价格+自定义字段值」,但你想要的是:比如变体价格49美元,自定义复选框价格79美元,购物车显示产品价格49美元,小计直接变成49+79=128美元(或按数量累加),同时结账金额也正确包含这笔费用。

解决方案

下面给你两种可行的方案,根据你的实际需求选择:

方案1:给每个购物车项添加单独的自定义费用(推荐)

这个方案会在购物车中添加一个清晰的自定义费用项,同时保持产品价格不变,订单总价也会正确计算:

// 计算并添加自定义费用到订单总价
function add_custom_item_fee( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;

    $total_custom_fee = 0;

    // 遍历每个购物车项
    foreach ( $cart->get_cart() as $cart_item ) {
        // 获取自定义字段的值
        $custom_fee = get_post_meta( $cart_item['product_id'], '_number_field_1', true );
        $custom_fee = floatval( $custom_fee );

        if ( $custom_fee > 0 ) {
            // 如果是每个商品都加一次费用,就乘以数量;如果是每个购物车项只加一次,去掉* $cart_item['quantity']
            $total_custom_fee += $custom_fee * $cart_item['quantity'];
        }
    }

    // 添加总自定义费用到购物车
    if ( $total_custom_fee > 0 ) {
        $cart->add_fee( '自定义选项费用', $total_custom_fee, true, '' );
    }
}
add_action( 'woocommerce_before_calculate_totals', 'add_custom_item_fee', 99 );

// 修改购物车项的小计显示,把自定义费用合并到小计里(可选,如果你想让小计直接显示总和)
function show_combined_subtotal( $subtotal, $product, $cart_item, $cart_item_key ) {
    $custom_fee = get_post_meta( $cart_item['product_id'], '_number_field_1', true );
    $custom_fee = floatval( $custom_fee );

    if ( $custom_fee > 0 ) {
        // 计算合并后的小计:(原价格 + 自定义费用) × 数量
        $combined_subtotal = ( $product->get_price() + $custom_fee ) * $cart_item['quantity'];
        $subtotal = wc_price( $combined_subtotal );
    }

    return $subtotal;
}
add_filter( 'woocommerce_cart_product_subtotal', 'show_combined_subtotal', 10, 4 );

// 可选:修改购物车中产品价格的显示,标注自定义费用
function display_price_with_custom_fee( $price, $cart_item ) {
    $custom_fee = get_post_meta( $cart_item['product_id'], '_number_field_1', true );
    $custom_fee = floatval( $custom_fee );

    if ( $custom_fee > 0 ) {
        $original_price = wc_price( $cart_item['data']->get_price() );
        $fee_display = wc_price( $custom_fee );
        $price = "$original_price + $fee_display";
    }

    return $price;
}
add_filter( 'woocommerce_cart_item_price', 'display_price_with_custom_fee', 10, 2 );

方案2:直接修改购物车项的小计计算(不显示单独费用项)

如果你不想显示单独的费用项,只想默默把自定义费用加到小计里,可以用这个方案:

function adjust_cart_item_subtotal( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;

    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        $custom_fee = get_post_meta( $cart_item['product_id'], '_number_field_1', true );
        $custom_fee = floatval( $custom_fee );

        if ( $custom_fee > 0 ) {
            // 获取原产品价格
            $original_price = $cart_item['data']->get_price();
            // 设置新的价格为原价格+自定义费用(这样小计会自动变成新价格×数量)
            // 但我们用一个临时元数据保存原价格,用来在显示时还原
            $cart_item['data']->set_price( $original_price + $custom_fee );
            $cart_item['data']->add_meta_data( '_original_price', $original_price, true );
        }
    }
}
add_action( 'woocommerce_before_calculate_totals', 'adjust_cart_item_subtotal', 99 );

// 还原购物车页面显示的产品价格为原价格
function restore_original_price_display( $price, $cart_item ) {
    if ( $cart_item['data']->get_meta( '_original_price' ) ) {
        $original_price = $cart_item['data']->get_meta( '_original_price' );
        $price = wc_price( $original_price );
    }
    return $price;
}
add_filter( 'woocommerce_cart_item_price', 'restore_original_price_display', 10, 2 );

为什么之前的尝试无效?

woocommerce_cart_product_subtotal这个钩子只是用来修改前端显示的小计文本,不会改变WooCommerce内部计算订单总价的逻辑,所以即使你修改了显示的数值,实际结账金额还是原来的,这就是你觉得无效的原因。必须通过woocommerce_before_calculate_totals钩子来修改实际的金额计算,才能让结账金额正确。

内容的提问来源于stack exchange,提问作者beginner115

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:15:48