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

WooCommerce商品页自定义百分比下拉菜单无法添加值至购物车

WooCommerce 颜色附加费功能修复方案

问题背景

需要在WooCommerce商品页面添加下拉选择字段,实现以下功能:

  • 基于商品价格(含税/不含税,根据客户所在地自动适配)收取百分比附加费
  • 保留颜色标签用于后续业务逻辑
  • 客户与管理员可在结账页、订单及邮件中查看对应颜色与支付金额
  • 若商品应税,附加费需包含税费
  • 允许相同百分比的选项重复显示(需保留对应颜色标签)

当前遇到的核心问题:选中的下拉值无法添加到购物车,以下为改编后的问题代码:

add_action('woocommerce_before_add_to_cart_button', 'product_option_custom_field', 30 );
function product_option_custom_field(){
    global $product;
    
    //$custom_subtotal = get_related_items_subtotal( WC()->cart );

    
    $active_price = (float) $product->get_price();
    
    // surcharge is % of item value, exc tax or inc tax
        $colour_surcharge    = strip_tags( wc_price( wc_get_price_to_display( $product, array('price' => $custom_subtotal ) ) ) ); 
   // $colour_price_html   = strip_tags( wc_price( wc_get_price_to_display( $product, array('price' => $custom_subtotal ) ) ) );
    $active_price_html   = wc_price( wc_get_price_to_display( $product ) );
    $disp_price_sum_html = wc_price( wc_get_price_to_display( $product, array('price' => $active_price + $custom_subtotal ) ) );
    
    
    $custom_subtotal = (float) $product->get_price();
    
     if ( $custom_subtotal > 0 ) {
        //  $value = WC()->session->get( 'colour_surcharge' );
       //  $value = empty( $value ) ? WC()->checkout->get_value( 'colour_surcharge' ) : $value;
         $value = empty( $value ) ? '0' : $value;
        $domain = 'woocommerce';
       // echo '<div id="checkout-select">
          //  <h4>' . __("Select Colour option") .'</h4>';
            

          woocommerce_form_field( 'colour_surcharge', array(
            'type' => 'select',
            'class' => array( 'form-row-wide', 'update_totals_on_change' ),
            'label'   => __( 'Colour options, standard or premium', 'woocommerce' ),
            'desc_tip'    => 'true',
            'description' => __( 'Select your chosen colour', 'woocommerce' ),
            'options' => array(
                 // 0 would be hidden, using 0.001 works to retain the values
                '0.001 black'  => __( 'Black - no fee', 'woocommerce' ) . ' (' . strip_tags( wc_price( 0.001 * $custom_subtotal / 100 ) ) . ')',
                '15 white' => __( 'White 15% surcharge', 'woocommerce' ) . ' (' . strip_tags( wc_price( 15 * $custom_subtotal / 100 ) ) . ')',
                '25 red' => __( 'Red 25% surcharge', 'woocommerce' ) . ' (' . strip_tags( wc_price( 25 * $custom_subtotal / 100 ) ) . ')',  
            ),
        ), $value );
        
             // Jquery: Update displayed price
    ?>
    <script type="text/javascript">
    jQuery(function($) {
        var cb = 'input[name="colour_surcharge"]'
            pp = 'p.price';

        // On change / select a variation
        $('form.cart').on( 'change', cb, function(){
            needs to be selected 
                 if( $(cb).prop('selected') === true )
           // if( $(cb).prop('checked') === true )
                $(pp).html('<?php echo $disp_price_sum_html; ?>');
            else
                $(pp).html('<?php echo $active_price_html; ?>');
        })

    });
    </script>
    <?php
}
}


function save_value_add_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
    $custom_fees = filter_input( INPUT_POST, 'custom_fees' );
    if ( empty( $custom_fees ) ) {
        return $cart_item_data;
    }
    $cart_item_data['colour_surcharge'] = $custom_fees;

    return $cart_item_data;
}

add_filter( 'woocommerce_add_cart_item_data', 'save_value_add_cart_item_data', 99, 3 );

function calculate_add_cart_fee() {
    global $woocommerce;
    $percentage = (float) WC()->session->get( 'colour_surcharge' );
    
    $cart_items = $woocommerce->cart->get_cart();
    foreach( $cart_items as $key => $item ) { 
             
        if ( $surcharge_fee === '0.001 black' ) {
            $label = sprintf( __('Black no fee %d%', 'woocommerce'), $percentage == 0.001 ? 0.001 : 15); 
            $cart->add_fee( $label, $custom_subtotal * $percentage / 100 );
    }
            elseif ( $surcharge_fee === '15 white' ) {
          $label = sprintf( __('Blue standard %d% fee', $domain), $percentage == 15 ? 15 : 35);
          $cart->add_fee( $label, $custom_subtotal * $percentage / 100 );
    }
            elseif ( $surcharge_fee === '35 red' ) {
          $label = sprintf( __('Red %d% fee', $domain), $percentage == 35 ? 15 : 35);
          $cart->add_fee( $label, $custom_subtotal * $percentage / 100 );
    }
        if( !isset( $item['colour_surcharge'] ) && empty( $item['colour_surcharge'] ) ) continue;
        $woocommerce->cart->add_fee( __('Colour Surcharge', 'woocommerce'), $item['colour_surcharge'] );
    }
}
add_action( 'woocommerce_cart_calculate_fees', 'calculate_add_cart_fee', 99 );

// Display custom data in  checkout page
add_filter( 'woocommerce_get_item_data', 'display_custom_cart_item_data', 10, 2 );
function display_custom_cart_item_data( $cart_data, $cart_item ) {
    $domain        = 'woocommerce';

    if ( isset( $cart_item['colour_surcharge'] ) ){
        $cart_data[] = array('name' => __( 'Colour Surcharge', $domain ),
            'value' => $cart_item['colour_surcharge'] );
    }
    return $cart_data;
}

add_action( 'woocommerce_admin_order_data_after_order_details', 'display_order_custom_meta_data_in_admin' );
function display_order_custom_meta_data_in_admin( $order ){
    $colour_surcharge = colour_surcharge_array();
    $key = get_post_meta( $order->get_id(), 'colour_surcharge', true );
    ?>
    <div class="order_data_column">
        <h4><?php _e( 'Colour Surcharge' ); ?></h4>
        <p><strong><?php _e( 'Colour Surcharge: ' ); ?></strong><?php echo $colour_surcharge[$key]; ?></p>
    </div>
    <?php
}

核心错误分析

  1. 表单字段与数据保存不匹配:表单字段名为colour_surcharge,但保存函数中读取的是custom_fees,导致无法获取选中值
  2. 变量未定义与逻辑混乱:计算附加费的函数中存在大量未定义变量(如$surcharge_fee、$cart),条件判断与实际选项不匹配
  3. jQuery选择器错误:下拉字段用input选择器定位,实际应为select,价格更新逻辑完全失效
  4. 管理员订单显示依赖缺失:调用未定义的colour_surcharge_array()函数,导致后台无法显示数据
  5. 税费处理缺失:未根据商品是否应税判断附加费是否含税

修复后的完整代码

// 商品页显示颜色选择下拉字段
add_action('woocommerce_before_add_to_cart_button', 'product_option_custom_field', 30 );
function product_option_custom_field(){
    global $product;
    
    $active_price = (float) $product->get_price();
    $active_price_html = wc_price( wc_get_price_to_display( $product ) );
    $domain = 'woocommerce';

    if ( $active_price > 0 ) {
        // 获取已选值(购物车中存在则保留)
        $value = isset($_POST['colour_surcharge']) ? sanitize_text_field($_POST['colour_surcharge']) : '0.001 black';

        woocommerce_form_field( 'colour_surcharge', array(
            'type' => 'select',
            'class' => array( 'form-row-wide', 'update_totals_on_change' ),
            'label'   => __( 'Colour options, standard or premium', 'woocommerce' ),
            'desc_tip'    => true,
            'description' => __( 'Select your chosen colour', 'woocommerce' ),
            'options' => array(
                '0.001 black'  => __( 'Black - no fee', 'woocommerce' ) . ' (' . strip_tags( wc_price( 0.001 * $active_price / 100 ) ) . ')',
                '15 white' => __( 'White 15% surcharge', 'woocommerce' ) . ' (' . strip_tags( wc_price( 15 * $active_price / 100 ) ) . ')',
                '25 red' => __( 'Red 25% surcharge', 'woocommerce' ) . ' (' . strip_tags( wc_price( 25 * $active_price / 100 ) ) . ')',
                '15 blue' => __( 'Blue 15% surcharge', 'woocommerce' ) . ' (' . strip_tags( wc_price( 15 * $active_price / 100 ) ) . ')', // 同百分比重复选项
            ),
        ), $value );
    ?>
    <script type="text/javascript">
    jQuery(function($) {
        var selectField = 'select[name="colour_surcharge"]';
        var priceElement = 'p.price';
        var basePrice = <?php echo $active_price; ?>;
        var basePriceHtml = '<?php echo $active_price_html; ?>';

        // 初始化价格显示
        updatePrice();

        // 选择变化时更新价格
        $('form.cart').on('change', selectField, function(){
            updatePrice();
        });

        function updatePrice() {
            var selectedValue = $(selectField).val();
            var percentage = parseFloat(selectedValue.split(' ')[0]);
            var surcharge = basePrice * percentage / 100;
            var totalPrice = basePrice + surcharge;
            var totalPriceHtml = wc_price(totalPrice);
            
            $(priceElement).html(totalPriceHtml);
        }
    });
    </script>
    <?php
    }
}

// 保存颜色选择到购物车项数据
add_filter( 'woocommerce_add_cart_item_data', 'save_colour_surcharge_to_cart', 99, 3 );
function save_colour_surcharge_to_cart( $cart_item_data, $product_id, $variation_id ) {
    if ( isset($_POST['colour_surcharge']) ) {
        $cart_item_data['colour_surcharge'] = sanitize_text_field($_POST['colour_surcharge']);
        // 添加唯一键确保同商品不同选项视为独立项
        $cart_item_data['unique_key'] = md5( microtime().rand() );
    }
    return $cart_item_data;
}

// 计算并添加颜色附加费
add_action( 'woocommerce_cart_calculate_fees', 'calculate_colour_surcharge_fee', 99 );
function calculate_colour_surcharge_fee() {
    if ( is_admin() && !defined('DOING_AJAX') ) return;

    foreach( WC()->cart->get_cart() as $cart_item ) {
        if ( isset($cart_item['colour_surcharge']) ) {
            $surcharge_data = explode(' ', $cart_item['colour_surcharge'], 2);
            $percentage = (float)$surcharge_data[0];
            $colour = isset($surcharge_data[1]) ? $surcharge_data[1] : '';
            
            if ( $percentage <= 0 ) continue;

            $product = $cart_item['data'];
            // 根据商品是否应税决定附加费是否含税
            $taxable = $product->is_taxable();
            $item_price = $taxable ? $product->get_price_excluding_tax() : $product->get_price_including_tax();
            $surcharge_amount = $item_price * $percentage / 100;

            // 生成显示标签
            $label = sprintf( __('Colour Surcharge (%s): %d%%', 'woocommerce'), $colour, $percentage );
            // 第三个参数为true表示附加费含税
            WC()->cart->add_fee( $label, $surcharge_amount, $taxable );
        }
    }
}

// 在购物车和结账页显示颜色选择信息
add_filter( 'woocommerce_get_item_data', 'display_colour_surcharge_in_cart', 10, 2 );
function display_colour_surcharge_in_cart( $cart_data, $cart_item ) {
    $domain = 'woocommerce';
    if ( isset( $cart_item['colour_surcharge'] ) ) {
        $surcharge_data = explode(' ', $cart_item['colour_surcharge'], 2);
        $percentage = (float)$surcharge_data[0];
        $colour = isset($surcharge_data[1]) ? $surcharge_data[1] : '';
        
        $display_value = $percentage == 0.001 ? __('Black - no fee', $domain) : sprintf( __('%s - %d%% surcharge', $domain), ucfirst($colour), $percentage );
        $cart_data[] = array(
            'name' => __( 'Colour Option', $domain ),
            'value' => $display_value
        );
    }
    return $cart_data;
}

// 保存颜色选择到订单元数据
add_action( 'woocommerce_checkout_create_order_line_item', 'save_colour_surcharge_to_order', 10, 4 );
function save_colour_surcharge_to_order( $item, $cart_item_key, $cart_item, $order ) {
    if ( isset($cart_item['colour_surcharge']) ) {
        $surcharge_data = explode(' ', $cart_item['colour_surcharge'], 2);
        $percentage = (float)$surcharge_data[0];
        $colour = isset($surcharge_data[1]) ? $surcharge_data[1] : '';
        
        $display_value = $percentage == 0.001 ? __('Black - no fee', 'woocommerce') : sprintf( __('%s - %d%% surcharge', 'woocommerce'), ucfirst($colour), $percentage );
        $item->add_meta_data( __( 'Colour Option', 'woocommerce' ), $display_value, true );
    }
}

// 在管理员订单页显示颜色选择信息
add_action( 'woocommerce_admin_order_data_after_order_details', 'display_colour_surcharge_in_admin_order' );
function display_colour_surcharge_in_admin_order( $order ){
    ?>
    <div class="order_data_column">
        <h4><?php _e( 'Colour Options' ); ?></h4>
        <?php foreach( $order->get_items() as $item ) {
            $colour_option = $item->get_meta( __( 'Colour Option', 'woocommerce' ) );
            if ( $colour_option ) {
                echo '<p><strong>' . __( 'Item:', 'woocommerce' ) . '</strong> ' . $item->get_name() . '</p>';
                echo '<p><strong>' . __( 'Colour Option:', 'woocommerce' ) . '</strong> ' . $colour_option . '</p><br>';
            }
        } ?>
    </div>
    <?php
}

修复后功能说明

  • 支持同百分比选项重复添加,每个选项保留独立颜色标签
  • 附加费自动适配商品含税/不含税状态,符合地区税费规则
  • 商品页实时更新显示价格,直观展示附加费变化
  • 购物车、结账页、订单详情(前台+后台)及邮件中均会显示所选颜色与对应附加费
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 07:39:58