
本文详解如何在 WooCommerce 中为商品同时展示“元/平方米”和“元/整箱”两种价格形式,并确保购物车与订单结算严格按整箱价格执行,兼顾展示灵活性与交易准确性。
本文详解如何在 woocommerce 中为商品同时展示“元/平方米”和“元/整箱”两种价格形式,并确保购物车与订单与订单结算严格按整箱价格执行,兼顾展示灵活性与交易准确性。
在实际建材、地板、瓷砖等类目电商场景中,商家常需以「单位面积价格(如 €100/m²)」作为参考报价,同时以「标准包装为销售单元(如 €170/箱,含 1.70m²)」完成交易。WooCommerce 原生仅支持单一价格逻辑,但通过自定义字段 + 钩子扩展,可优雅实现「双价展示、单价结算」的业务需求。
以下方案分为三步实现:添加后台输入字段 → 安全保存数据 → 前端展示双价 → 保障结算一致性(关键!原答案未覆盖结算逻辑,此处补全):
1. 添加后台自定义字段(每箱含多少平方米)
// 在商品库存选项卡下添加「每箱平方米数」输入框(仅对简单商品生效)
add_action('woocommerce_product_options_inventory_product_data', function() {
woocommerce_wp_text_input([
'id' => '_m2_per_box',
'label' => __('每箱含 m² 数', 'textdomain'),
'description' => __('例如:1.70(表示每箱含 1.70 平方米)', 'textdomain'),
'type' => 'number',
'step' => '0.01',
'wrapper_class' => 'show_if_simple'
]);
});2. 保存并验证自定义字段
// 保存时校验数值合法性(正数、保留两位小数)
add_action('woocommerce_process_product_meta', function($post_id) {
if (isset($_POST['_m2_per_box']) && is_numeric($_POST['_m2_per_box']) && $_POST['_m2_per_box'] > 0) {
$m2_per_box = round(floatval($_POST['_m2_per_box']), 2);
update_post_meta($post_id, '_m2_per_box', $m2_per_box);
}
});3. 前端展示双价(产品页 & 列表页)
// 在商品摘要区(标题下方)显示双价信息
add_action('woocommerce_single_product_summary', function() {
global $product;
$regular_price = $product->get_regular_price();
$m2_per_box = $product->get_meta('_m2_per_box');
if ($regular_price > 0 && !empty($m2_per_box)) {
$price_per_m2 = round($regular_price / $m2_per_box, 2);
echo '<div class="woocommerce-price-display" style="margin: 1em 0; padding: 0.5em; background:#f9f9f9; border-left:3px solid #4CAF50;">';
echo '<strong>' . __('参考单价:', 'textdomain') . '</strong>' . wc_price($price_per_m2) . '/m²<br>';
echo '<strong>' . __('整箱售价:', 'textdomain') . '</strong>' . wc_price($regular_price) . '/箱(含 ' . $m2_per_box . 'm²)';
echo '</div>';
}
}, 11);
// 可选:在商品列表页(shop loop)也显示参考单价
add_action('woocommerce_after_shop_loop_item_title', function() {
global $product;
$regular_price = $product->get_regular_price();
$m2_per_box = $product->get_meta('_m2_per_box');
if ($regular_price > 0 && !empty($m2_per_box)) {
$price_per_m2 = round($regular_price / $m2_per_box, 2);
echo '<small class="price-per-m2">' . sprintf(__('≈ %s/m²', 'textdomain'), wc_price($price_per_m2)) . '</small><br>';
}
}, 11);⚠️ 关键保障:强制按整箱结算(防止用户误购非整箱数量)
WooCommerce 默认允许任意数量加购,但本业务要求「必须整箱购买」。需叠加以下逻辑:
// 强制最小购买数量 = 1 箱,且只能以整箱倍数购买
add_filter('woocommerce_quantity_input_args', function($args, $product) {
$m2_per_box = $product->get_meta('_m2_per_box');
if (!empty($m2_per_box)) {
$args['min_value'] = 1;
$args['step'] = 1; // 禁用小数数量
$args['input_value'] = 1; // 默认值设为 1 箱
}
return $args;
}, 10, 2);
// 加购前校验:若用户尝试输入非整数数量,自动修正
add_action('woocommerce_add_to_cart_redirect', function($url) {
$quantity = isset($_REQUEST['quantity']) ? intval($_REQUEST['quantity']) : 1;
if ($quantity < 1) {
wc_add_notice(__('购买数量至少为 1 箱。', 'textdomain'), 'error');
return $url;
}
return $url;
});
// (进阶)隐藏「数量选择器」,仅显示「加入购物车」按钮(更符合箱装逻辑)
// add_action('woocommerce_before_add_to_cart_button', 'hide_quantity_field_for_boxed_products');
// function hide_quantity_field_for_boxed_products() {
// global $product;
// if (!empty($product->get_meta('_m2_per_box'))) {
// echo '<style>.quantity, .qty { display:none; }</style>';
// }
// }总结与注意事项
- ✅ 展示层:通过
_m2_per_box字段动态计算并呈现€/m²参考价 +€/箱实际售价; - ✅ 结算层:WooCommerce 原生
regular_price即为箱价,无需修改价格逻辑,仅需约束购买数量; - ⚠️ 避免混淆:切勿使用
sale_price或价格过滤器(如woocommerce_get_price_html)覆盖主价格,否则将破坏订单金额; - ? 数据安全:所有
$_POST输入均需类型校验与数值范围限制,防止注入或异常数据; - ? 扩展建议:如需支持多规格(如不同箱型),可升级为自定义产品变体(variation),每个变体独立设置
_m2_per_box和价格。
该方案轻量、稳定、符合 WooCommerce 最佳实践,既满足买家直观比价需求,又确保商家收款逻辑零偏差。

















