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&#37;', '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&#37; fee', $domain), $percentage == 15 ? 15 : 35); $cart->add_fee( $label, $custom_subtotal * $percentage / 100 ); } elseif ( $surcharge_fee === '35 red' ) { $label = sprintf( __('Red %d&#37; 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 }
核心错误分析
- 表单字段与数据保存不匹配:表单字段名为
colour_surcharge,但保存函数中读取的是custom_fees,导致无法获取选中值 - 变量未定义与逻辑混乱:计算附加费的函数中存在大量未定义变量(如
$surcharge_fee、$cart),条件判断与实际选项不匹配 - jQuery选择器错误:下拉字段用
input选择器定位,实际应为select,价格更新逻辑完全失效 - 管理员订单显示依赖缺失:调用未定义的
colour_surcharge_array()函数,导致后台无法显示数据 - 税费处理缺失:未根据商品是否应税判断附加费是否含税
修复后的完整代码
// 商品页显示颜色选择下拉字段 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 }
修复后功能说明
- 支持同百分比选项重复添加,每个选项保留独立颜色标签
- 附加费自动适配商品含税/不含税状态,符合地区税费规则
- 商品页实时更新显示价格,直观展示附加费变化
- 购物车、结账页、订单详情(前台+后台)及邮件中均会显示所选颜色与对应附加费
相关产品推荐
相关产品推荐

