如何在 WooCommerce 购物车中为不同商品添加差异化附加费用
在运营 WooCommerce 电子商务网站时,商家常常会遇到需要为特定商品添加额外费用的情况。例如,大件商品需要额外的包装费,易碎品需要特殊处理费,或者定制商品需要附加的手工费。WooCommerce 默认的附加费用设置通常是全局性的,无法针对购物车中的不同商品进行差异化收费。为了实现这一需求,我们需要借助 WooCommerce 提供的钩子进行自定义开发。
WooCommerce 附加费用机制简介
在 WooCommerce 中,所有关于购物车费用的计算都离不开一个核心钩子:woocommerce_cart_calculate_fees。通过这个钩子,开发者可以在购物车计算总价时,动态地注入自定义的附加费用。该钩子允许我们访问购物车对象,遍历其中的商品,并根据商品属性(如 ID、分类、标签等)来决定是否添加费用以及添加多少费用。
实现差异化附加费用的核心逻辑
要为不同商品添加差异化费用,核心逻辑分为三步:
获取购物车中的所有商品。
遍历商品,判断当前商品是否满足添加附加费用的条件(如特定的商品 ID 或属于特定的分类)。
如果满足条件,则根据商品数量或固定金额计算费用,并使用
WC_Cart->add_fee()方法将费用添加到购物车中。
代码实现:基于商品 ID 添加附加费用
假设我们有两个商品:商品 A(ID 为 10)需要增加 5 美元的特殊包装费,商品 B(ID 为 20)需要增加 10 美元的大件运输费。我们可以将以下代码添加到主题的 functions.php 文件或自定义插件中:
<?php
add_action( 'woocommerce_cart_calculate_fees', 'add_custom_fee_by_product_id', 10, 1 );
function add_custom_fee_by_product_id( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
$fee_data = array(
10 => 5, // 商品 ID 为 10 时,附加 5 单位费用
20 => 10, // 商品 ID 为 20 时,附加 10 单位费用
);
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$product_id = $cart_item['product_id'];
$quantity = $cart_item['quantity'];
if ( isset( $fee_data[ $product_id ] ) ) {
$fee_amount = $fee_data[ $product_id ] * $quantity;
$product_name = $cart_item['data']->get_name();
$fee_name = sprintf( '%s - 附加费用', $product_name );
$cart->add_fee( __( $fee_name, 'text-domain' ), $fee_amount, true );
}
}
}在这段代码中,我们定义了一个数组 $fee_data 来映射商品 ID 和对应的费用。遍历购物车时,如果商品 ID 存在于数组中,就将费用乘以商品数量,并以“商品名称 - 附加费用”的形式添加到结账明细中。注意 add_fee() 方法的第三个参数 true 表示该费用需要计算税费。
代码实现:基于商品分类添加附加费用
如果商品数量众多,逐个指定商品 ID 会非常繁琐。此时,按商品分类添加附加费用是更好的选择。假设属于“易碎品”分类(分类 ID 为 15)的商品都需要增加 8 美元的保价费,代码如下:
<?php
add_action( 'woocommerce_cart_calculate_fees', 'add_custom_fee_by_product_category', 10, 1 );
function add_custom_fee_by_product_category( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
$target_category_id = 15; // 目标分类 ID
$fee_amount_per_item = 8; // 每件商品的附加费用
$total_fee = 0;
$has_fragile_item = false;
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$product_id = $cart_item['product_id'];
$quantity = $cart_item['quantity'];
$terms = get_the_terms( $product_id, 'product_cat' );
if ( $terms && ! is_wp_error( $terms ) ) {
foreach ( $terms as $term ) {
if ( $term->term_id == $target_category_id ) {
$total_fee += $fee_amount_per_item * $quantity;
$has_fragile_item = true;
break;
}
}
}
}
if ( $has_fragile_item && $total_fee > 0 ) {
$cart->add_fee( __( '易碎品保价费', 'text-domain' ), $total_fee, true );
}
}这段代码首先获取购物车中每个商品的分类信息。如果发现商品属于指定的分类,就累加费用。最后,如果购物车中存在易碎品且总费用大于 0,则统一添加一笔名为“易碎品保价费”的附加项。这种方法可以避免为同一分类下的多个商品重复生成费用行,使账单更加简洁。
进阶技巧与注意事项
在实施差异化附加费用时,有几个关键点需要特别注意:
费用名称的唯一性:在
add_fee()方法中,第一个参数是费用名称。如果购物车中有多个商品都触发了基于 ID 的附加费用,确保每个费用名称是唯一的(如上文代码中拼接了商品名称),否则后添加的费用会覆盖前面的费用。税费计算:
add_fee()的第三个参数控制费用是否含税。设置为true表示费用将按照购物车的税率计算税费,设置为false则表示该费用为最终价格,不再额外加税。请根据当地税务法规合理设置。性能优化:在按分类查询时,如果购物车商品非常多,频繁调用数据库查询分类可能会产生轻微的性能损耗。可以考虑使用 WordPress 的对象缓存机制,或者在循环外提前获取所有分类的映射关系以减少查询次数。
前端提示:为了提高用户体验,建议在商品详情页使用
<div>或<span>标签提示用户该商品可能产生额外费用,避免在结账时引起用户疑惑和弃单。同时,若你的费率规则需要动态拉取,可通过 API 接口请求(例如请求 https://www.ipipp.com 获取最新费率配置),请务必做好异常处理,保证费率规则的及时更新与容错。
总结
通过灵活运用 woocommerce_cart_calculate_fees 钩子,结合对商品 ID 或分类的判断,我们可以在 WooCommerce 购物车中轻松实现差异化的附加费用。这不仅弥补了 WooCommerce 默认功能的不足,还能帮助商家更精确地覆盖运营成本。在实际开发中,务必注意费用命名的唯一性以及税费合规性,从而为消费者提供清晰透明的结账体验。