我创建了以下函数来覆盖产品价格,并为WooCommerce提供最大折扣。然而,我似乎不明白为什么woocommerce_coupon_get_discount_amount过滤器适用于所有优惠券。
我试图让它发挥作用的方法是,如果优惠券是一个百分比的优惠券,它将限制该优惠券的总折扣金额。如果优惠券是fixed_cart类型,并且它有我添加的_price_per_product_amt填充的自定义字段,那么它将改变产品的价格。
如果我在购物车里只有一张优惠券,这两种功能都能工作。如果购物车中有fixed_cart_coupon,它将更改价格并将优惠券金额设置为0美元(优惠券设置为0美元)。但是,如果我也添加了一个百分比优惠券,这个函数可以用于百分比优惠券,但是它也为fixed_cart_coupon添加了一个折扣金额。它只应该修改购物车中的百分比优惠券的折扣金额。

// filter to change discount if over max coupon amount
function filter_woocommerce_coupon_get_discount_amount( $discount, $discounting_amount, $cart_item, $single, $instance ) {
$cartCoupons = WC()->cart->get_applied_coupons();
foreach ($cartCoupons as $key => $appliedCoupon) {
$coupon = new WC_Coupon($appliedCoupon);
$couponType = get_post_meta( $coupon->get_id(), 'discount_type', true );
if ($couponType == 'percent') {
$maxCouponAmount = get_post_meta( $coupon->get_id(), '_max_discount', true );
$excludedProducts = explode(",", get_post_meta( $coupon->get_id(), 'exclude_product_ids', true ));
$cartLines = count(WC()->cart->get_cart());
$cartLineItems = WC()->cart->get_cart();
foreach ($cartLineItems as $cartItem){
$cartProductID[] = $cartItem['product_id'];
if (!empty($excludedProducts)) {
$cartLinesWithoutExcluded = array_intersect($cartProductID,$excludedProducts);
} else {
$cartLinesWithoutExcluded = $cartProductID;
}
$cartLinesWithoutExcluded = count($cartLinesWithoutExcluded);
$totalCartItems = $cartLines - $cartLinesWithoutExcluded;
$discount = $maxCouponAmount / $totalCartItems;
}
} else {
$discount = 0.00;
}
return $discount;
}
}
// apply the coupon whether it is max discount or a product price adjustment
function apply_max_amount_or_product_price_adjustment(){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
if ( !is_admin() && !wp_is_json_request() ) {
global $wp, $woocommerce;
$cartCoupons = WC()->cart->get_applied_coupons();
foreach ($cartCoupons as $key => $appliedCoupon) {
$coupon = new WC_Coupon($appliedCoupon);
$maxCouponAmount = get_post_meta( $coupon->get_id(), '_max_discount', true );
$excludedProducts = explode(",", get_post_meta( $coupon->get_id(), 'exclude_product_ids', true ));
$couponType = get_post_meta( $coupon->get_id(), 'discount_type', true );
// $fixedProductPrice = get_post_meta( $coupon->get_id(), '_adjust_price', true );
$couponAmount = WC()->cart->get_coupon_discount_amount( $appliedCoupon );
if (!empty($maxCouponAmount) && $couponType == 'percent' && ($couponAmount > $maxCouponAmount || $couponAmount == $maxCouponAmount)) {
add_filter( 'woocommerce_coupon_get_discount_amount', 'filter_woocommerce_coupon_get_discount_amount', 10, 5 );
}
if ($couponType == 'fixed_cart'){
$cart = WC()->cart->get_cart();
$couponProducts = explode(',',get_post_meta( $coupon->get_id(), 'product_ids', true ));
$fixedPricePerProduct = get_post_meta( $coupon->get_id(), '_price_per_product_amt', true );
foreach( $cart as $cart_item ) {
if (in_array($cart_item['data']->get_parent_id(), $couponProducts)) {
$cart_item['data']->set_price( $fixedPricePerProduct );
}
}
}
}
}
}
add_action('woocommerce_before_calculate_totals', 'apply_max_amount_or_product_price_adjustment', 10, 1);发布于 2021-12-12 01:39:20
我似乎不明白为什么woocommerce_coupon_get_discount_amount过滤器适用于所有优惠券。
这是因为当您从函数'filter_woocommerce_coupon_get_discount_amount‘中添加过滤器'apply_max_amount_or_product_price_adjustment',时,它将被添加到所有优惠券中。稍后会触发此筛选器,因此应用或不应用它的条件将无法工作(因为它已被添加)。您应该删除添加筛选器的部分,并在此函数之外设置筛选器。
在添加任何筛选器时,即使在条件中,由于添加了过滤器,每次都会添加筛选器,直到remove_filter( . )将其删除为止。在您的例子中,您不能在'apply_max_amount_or_product_price_adjustment‘中使用remove_filter,因为它是早期的,并且将为所有的优惠券事件“%”类型删除它。
但是,如果我也添加了百分比优惠券,则该函数适用于百分比优惠券,但它也会向fixed_cart_coupon添加折扣金额。
这是因为您正在循环筛选器'filter_woocommerce_coupon_get_discount_amount‘中的所有优惠券,并且总是从第一个优惠券返回值。这个过滤器每次有$优惠券->get_ fire _amount()时就会触发,因此它会在结帐时触发应用在购物车上的每一张优惠券。您应该删除循环,只检查当前的优惠券。为了更好地理解,您应该将参数'$instance‘重命名为'$coupon’,这是当前的WC_Coupon对象。
您可以查看WC_Coupon类并搜索筛选器'woocommerce_coupon_get_discount_amount‘( ctrl +f以在页面中找到它)如下:https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/includes/class-wc-coupon.php
此外,在您的循环中要小心:
foreach ($cartLineItems as $cartItem){
$cartProductID[] = $cartItem['product_id'];
if (!empty($excludedProducts)) {
$cartLinesWithoutExcluded = array_intersect($cartProductID,$excludedProducts);
} else {
$cartLinesWithoutExcluded = $cartProductID;
}
$cartLinesWithoutExcluded = count($cartLinesWithoutExcluded);
$totalCartItems = $cartLines - $cartLinesWithoutExcluded;
$discount = $maxCouponAmount / $totalCartItems;
}
// here $discount is the one calculated in last loop like all previous loops didn't exists. (same thing for $cartLinesWithoutExcluded and $totalCarItems)因为它总是只返回最后一个购物车项目的$discount。
尝试以下代码(未测试):
add_filter( 'woocommerce_coupon_get_discount_amount', 'filter_woocommerce_coupon_get_discount_amount', 10, 5 ); // add filter for all coupons
// filter to change discount if over max coupon amount
function filter_woocommerce_coupon_get_discount_amount( $discount, $discounting_amount, $cart_item, $single, $coupon ) {
// remove loop on applied coupons because you are managing coupon that is currently applied to the cart
if ( $coupon->is_type( 'percent' ) ) {
$maxCouponAmount = get_post_meta( $coupon->get_id(), '_max_discount', true );
// TRY TO REMOVE THIS FOR TESTING
// OR TRY TO return $maxCouponAmount to check this value
if ( empty( $maxCouponAmount ) ) { // do not change coupon discount if no max_discount
return $discount;
}
// ---
$excludedProducts = explode(",", get_post_meta( $coupon->get_id(), 'exclude_product_ids', true ));
$cartLines = count(WC()->cart->get_cart());
$cartLineItems = WC()->cart->get_cart();
// Changes in your loop
$cartLinesWithoutExcluded = 0; // *** UPDATE HERE
foreach ($cartLineItems as $cartItem){
$cartProductID[] = $cartItem['product_id'];
if (!empty($excludedProducts)) {
$cartLinesWithoutExcluded += count ( array_intersect($cartProductID,$excludedProducts) );
} else {
$cartLinesWithoutExcluded += count ( $cartProductID );
}
}
$totalCartItems = $cartLines - $cartLinesWithoutExcluded;
$discount = $totalCartItems > 0 ? $maxCouponAmount / $totalCartItems : 0; // Never divide by 0 !
// end of changes in your loop
} elseif ( $coupon->is_type( 'fixed_cart' ) ) {
$discount = 0.00;
}
return $discount;
}
// apply the coupon whether it is max discount or a product price adjustment
function apply_max_amount_or_product_price_adjustment(){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
if ( !is_admin() && !wp_is_json_request() ) {
global $wp, $woocommerce;
$cartCoupons = WC()->cart->get_applied_coupons();
foreach ($cartCoupons as $key => $appliedCoupon) {
$coupon = new WC_Coupon($appliedCoupon);
$maxCouponAmount = get_post_meta( $coupon->get_id(), '_max_discount', true );
$excludedProducts = explode(",", get_post_meta( $coupon->get_id(), 'exclude_product_ids', true ));
$couponType = get_post_meta( $coupon->get_id(), 'discount_type', true );
// $fixedProductPrice = get_post_meta( $coupon->get_id(), '_adjust_price', true );
$couponAmount = WC()->cart->get_coupon_discount_amount( $appliedCoupon );
// removed adding filter here
if ($couponType == 'fixed_cart'){
$cart = WC()->cart->get_cart();
$couponProducts = explode(',',get_post_meta( $coupon->get_id(), 'product_ids', true ));
$fixedPricePerProduct = get_post_meta( $coupon->get_id(), '_price_per_product_amt', true );
foreach( $cart as $cart_item ) {
if (in_array($cart_item['data']->get_parent_id(), $couponProducts)) {
$cart_item['data']->set_price( $fixedPricePerProduct );
}
}
}
}
}
}
add_action('woocommerce_before_calculate_totals', 'apply_max_amount_or_product_price_adjustment', 10, 1);如有必要,请测试和编辑代码。对不起,如果我的解释似乎混乱,我是在半夜写作。
https://stackoverflow.com/questions/70313775
复制相似问题