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

基于自定义输入字段更新WooCommerce产品价格的异常问题

问题:自定义字段导致购物车价格重复计算

我在单个产品页面添加了自定义数字输入字段,产品常规价格会乘以该字段输入的数值。比如基础价格10美元,用户输入2时,新价格变为20美元。产品页面价格更新正常,但进入购物车修改产品数量时,价格会被重复计算——已计算好的20美元,把数量从1改为5时,会再次乘以自定义数值2,最终价格变成40美元。

原使用代码:

add_action( 'woocommerce_after_add_to_cart_quantity', 'add_custom_input_number_field', 0 );
function add_custom_input_number_field() {
    echo '<div class="custom-input-number-field">';
    echo '<label>' . __( 'Custom Input Number', 'woocommerce' ) . '</label>';
    echo '<input type="number" required="true" placeholder="max. 30.500" class="custom-input-number" name="custom_input_number" min="1" step="0.001" />';
    echo '</div>';
}

add_filter( 'woocommerce_get_price_html', 'update_product_price_based_on_custom_input_on_product_page', 9999, 2 );
function update_product_price_based_on_custom_input_on_product_page( $price, $product ) {
    if ( is_product() && isset( $_POST['custom_input_number'] ) ) {
        $custom_input_value = (float) $_POST['custom_input_number'];
        $product_price = $product->get_price();
        $new_price = $product_price * $custom_input_value;
        $price = wc_price( $new_price ) . $product->get_price_suffix();
    }
    return $price;
}

add_filter( 'woocommerce_add_cart_item_data', 'save_custom_input_number_field_data', 10, 2 );
function save_custom_input_number_field_data( $cart_item_data, $product_id ) {
    if ( isset( $_POST['custom_input_number'] ) ) {
        $cart_item_data['custom_input_number'] = wc_clean( $_POST['custom_input_number'] );
        $cart_item_data['custom_input_number'] = (float) $cart_item_data['custom_input_number'];
    }
    return $cart_item_data;
}

add_action( 'woocommerce_before_calculate_totals', 'update_product_price_based_on_custom_input_in_cart', 10, 1 );
function update_product_price_based_on_custom_input_in_cart( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }
 
    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        if ( isset( $cart_item['custom_input_number'] ) ) {
            $custom_input_value = $cart_item['custom_input_number'];
            $product = $cart_item['data'];
            $product_price = $product->get_price();
            $new_price = $product_price * $custom_input_value;
            $product->set_price( $new_price );
        }
    }
}

问题原因

  1. 购物车价格计算逻辑错误:woocommerce_before_calculate_totals钩子每次触发(比如修改数量、更新购物车)时,$product->get_price()获取的是已经被修改后的价格,而非产品原始价格。这导致每次更新都会重复乘以自定义值,造成价格叠加计算。
  2. 产品页面价格更新依赖POST:原woocommerce_get_price_html的实现只有在提交表单时才会更新价格,用户输入自定义值时无法实时看到价格变化,体验不佳。

修正方案

1. 保留自定义字段添加函数

这部分不需要修改,继续使用:

add_action( 'woocommerce_after_add_to_cart_quantity', 'add_custom_input_number_field', 0 );
function add_custom_input_number_field() {
    echo '<div class="custom-input-number-field">';
    echo '<label>' . __( 'Custom Input Number', 'woocommerce' ) . '</label>';
    echo '<input type="number" required="true" placeholder="max. 30.500" class="custom-input-number" name="custom_input_number" min="1" step="0.001" />';
    echo '</div>';
}

2. 产品页面实时更新价格(JavaScript)

替换原woocommerce_get_price_html的PHP实现,用JS实时监听输入变化并更新价格:

add_action( 'woocommerce_single_product_summary', 'add_custom_price_update_script', 25 );
function add_custom_price_update_script() {
    global $product;
    $original_price = (float) $product->get_price();
    ?>
    <script>
        jQuery(document).ready(function($) {
            const originalPrice = <?php echo $original_price; ?>;
            const priceElement = $('.price .woocommerce-Price-amount');
            const suffix = '<?php echo esc_js($product->get_price_suffix()); ?>';
            
            $('.custom-input-number').on('input', function() {
                const customValue = parseFloat($(this).val()) || 1;
                const newPrice = originalPrice * customValue;
                const formattedPrice = new Intl.NumberFormat('<?php echo get_locale(); ?>', {
                    style: 'currency',
                    currency: '<?php echo get_woocommerce_currency(); ?>'
                }).format(newPrice);
                
                priceElement.html(formattedPrice + suffix);
            });
        });
    </script>
    <?php
}

3. 保存自定义值与产品原始价格

修改woocommerce_add_cart_item_data函数,同时保存产品的原始价格,确保后续计算时使用未修改的价格:

add_filter( 'woocommerce_add_cart_item_data', 'save_custom_input_and_original_price', 10, 3 );
function save_custom_input_and_original_price( $cart_item_data, $product_id, $variation_id ) {
    $product = wc_get_product( $variation_id ?: $product_id );
    
    if ( isset( $_POST['custom_input_number'] ) ) {
        $cart_item_data['custom_input_number'] = (float) wc_clean( $_POST['custom_input_number'] );
        // 保存产品原始价格,避免后续计算时使用修改后的值
        $cart_item_data['original_product_price'] = (float) $product->get_price();
        // 添加唯一键,确保每个自定义输入的商品都是独立的购物车项
        $cart_item_data['unique_key'] = md5( microtime() . rand() );
    }
    
    return $cart_item_data;
}

4. 修正购物车价格计算逻辑

修改woocommerce_before_calculate_totals函数,使用保存的原始价格乘以自定义值,避免重复计算:

add_action( 'woocommerce_before_calculate_totals', 'update_cart_price_with_custom_input', 10, 1 );
function update_cart_price_with_custom_input( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }

    // 防止循环调用
    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) {
        return;
    }
 
    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        if ( isset( $cart_item['custom_input_number'], $cart_item['original_product_price'] ) ) {
            $custom_input_value = $cart_item['custom_input_number'];
            $original_price = $cart_item['original_product_price'];
            $product = $cart_item['data'];
            
            // 用原始价格乘以自定义值,得到正确的单价
            $new_price = $original_price * $custom_input_value;
            $product->set_price( $new_price );
        }
    }
}

5. 购物车页面显示自定义字段(可选)

如果需要在购物车页面显示用户输入的自定义值,可以添加以下代码:

add_filter( 'woocommerce_get_item_data', 'display_custom_input_in_cart', 10, 2 );
function display_custom_input_in_cart( $item_data, $cart_item ) {
    if ( isset( $cart_item['custom_input_number'] ) ) {
        $item_data[] = array(
            'key'     => __( 'Custom Input Number', 'woocommerce' ),
            'value'   => wc_clean( $cart_item['custom_input_number'] ),
            'display' => '',
        );
    }
    return $item_data;
}

说明

  • 保存原始价格到购物车项数据中,确保每次计算都基于产品的初始价格,避免重复叠加自定义值。
  • 用JavaScript实现产品页面实时价格更新,提升用户体验。
  • 添加唯一键确保每个自定义输入的商品作为独立购物车项,避免同一款产品不同自定义值的价格冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 17:37:34