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

WooCommerce基于用户输入动态计算产品价格问题排查

WooCommerce自定义字段计算价格失败问题排查与修复

问题背景

店铺内15款产品需支持2000+变体,因WooCommerce默认变体上限限制,使用产品额外选项插件创建以下自定义输入字段:

  • 宽度(Width)、高度(Height)、厚度(Thickness)、材料类型(Material Type)
  • 材料密度对应:MDF=760,Chipboard=680
  • 重量计算公式:(宽度×高度×厚度×材料密度)/1000000000
  • Rate计算公式:重量×高度
  • 价格规则:
    • 2600≤Rate≤5349 → 价格1000
    • 5350≤Rate≤8999 → 价格2000
    • 9000≤Rate≤17250 → 价格3000

自行编写的PHP代码无法正确设置计算后的价格,以下是错误原因分析及修复方案。

错误原因

  1. $_POST数据无法持久获取:woocommerce_before_calculate_totals钩子触发时,添加商品时的$_POST自定义字段数据已不存在,仅在添加瞬间有效,后续购物车刷新、结算时无法拿到值。
  2. 未存储自定义字段到购物车项:没有将用户输入的参数保存到购物车项数据中,导致后续计算无数据源。
  3. 全局产品价格修改风险:直接修改$product->set_price()会影响所有该产品的价格,而非当前购物车项的专属价格。
  4. 缺少数据验证:未校验用户输入是否为有效数字,易导致计算逻辑出错。

修复后的完整代码

1. 保存自定义字段到购物车项

捕获添加商品时的自定义输入,存储到购物车项数据中:

add_filter('woocommerce_add_cart_item_data', 'save_custom_product_options_to_cart', 10, 3);
function save_custom_product_options_to_cart($cart_item_data, $product_id, $variation_id) {
    if(isset($_POST['height'], $_POST['width'], $_POST['thickness'], $_POST['type_de_bois'])) {
        // 验证并转换为数值类型
        $height = is_numeric($_POST['height']) ? floatval($_POST['height']) : 0;
        $width = is_numeric($_POST['width']) ? floatval($_POST['width']) : 0;
        $thickness = is_numeric($_POST['thickness']) ? floatval($_POST['thickness']) : 0;
        $material_type = sanitize_text_field($_POST['type_de_bois']);

        // 存储自定义选项到购物车项
        $cart_item_data['custom_options'] = [
            'height' => $height,
            'width' => $width,
            'thickness' => $thickness,
            'material_type' => $material_type
        ];

        // 添加唯一标识,确保同一商品不同选项视为独立购物车项
        $cart_item_data['unique_key'] = md5(microtime() . rand());
    }
    return $cart_item_data;
}

2. 购物车页面显示自定义选项(可选)

让用户在购物车中看到自己输入的参数:

add_filter('woocommerce_get_item_data', 'display_custom_options_in_cart', 10, 2);
function display_custom_options_in_cart($item_data, $cart_item) {
    if(isset($cart_item['custom_options'])) {
        $opts = $cart_item['custom_options'];
        $item_data[] = ['key' => '门高度', 'value' => "{$opts['height']} mm"];
        $item_data[] = ['key' => '门宽度', 'value' => "{$opts['width']} mm"];
        $item_data[] = ['key' => '厚度', 'value' => "{$opts['thickness']} mm"];
        $item_data[] = ['key' => '材料类型', 'value' => $opts['material_type'] === 'MDF' ? '中密度板(MDF)' : '刨花板'];
    }
    return $item_data;
}

3. 计算并设置购物车项价格

从购物车项中读取存储的自定义参数,计算后设置专属价格:

add_action('woocommerce_before_calculate_totals', 'update_cart_item_price_based_on_options', 10, 1);
function update_cart_item_price_based_on_options($cart) {
    // 避免后台执行逻辑冲突
    if(is_admin() && !defined('DOING_AJAX')) return;

    foreach($cart->get_cart() as $cart_item_key => $cart_item) {
        // 跳过无自定义选项的商品
        if(!isset($cart_item['custom_options'])) continue;

        $opts = $cart_item['custom_options'];
        $height = $opts['height'];
        $width = $opts['width'];
        $thickness = $opts['thickness'];
        $material_type = $opts['material_type'];

        // 计算材料密度
        $density = $material_type === 'MDF' ? 760 : 680;

        // 计算重量和Rate
        $weight = ($height * $width * $thickness * $density) / 1000000000;
        $rate = $weight * $height;

        // 根据Rate区间设置价格
        $price = 0;
        if($rate >= 2600 && $rate <= 5349) {
            $price = 1000;
        } elseif($rate >= 5350 && $rate <= 8999) {
            $price = 2000;
        } elseif($rate >= 9000 && $rate <= 17250) {
            $price = 3000;
        }

        // 设置当前购物车项的价格
        if($price > 0) {
            $cart_item['data']->set_price($price);
        }
    }
}

4. 保存自定义选项到订单(可选)

确保订单记录中保留用户输入的参数,方便后续核对:

add_action('woocommerce_checkout_create_order_line_item', 'save_custom_options_to_order', 10, 4);
function save_custom_options_to_order($item, $cart_item_key, $cart_item, $order) {
    if(isset($cart_item['custom_options'])) {
        $opts = $cart_item['custom_options'];
        $item->add_meta_data('门高度', "{$opts['height']} mm", true);
        $item->add_meta_data('门宽度', "{$opts['width']} mm", true);
        $item->add_meta_data('厚度', "{$opts['thickness']} mm", true);
        $item->add_meta_data('材料类型', $opts['material_type'] === 'MDF' ? '中密度板(MDF)' : '刨花板', true);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 08:34:51