archvist
archvist

Reputation: 722

Apply a discount based on ACF field to cart total in WooCommerce

I'm trying to create a discount programmatically for orders on my store. My users have a variable discount rate e.g. 10%. I want to apply their discount to the order before checkout, however, some items in the store are not applicable for a discount.

These items have a toggle set so I can check which products do or do not allow the discount to be applied.

Currently, I'm looping through the order to check which items are applicable and using a 'fixed_cart'coupon to add the discount.

This works, however, the in the admin the coupon applies to all line items even the items which should be skipped. Making it impossible to work how much to refund to customers when a refund is required.

Checking the cart items

$tradeDiscountTotal = 0;
foreach( WC()->cart->get_cart() as $cart_item ) {
    if(!get_field('trade_discount_exempt', $cart_item['product_id'])) {
        $tradeDiscountTotal += $cart_item['line_subtotal'];
    }
}

Applying the total discount for this order

$coupon->set_discount_type('fixed_cart');
$coupon->set_amount($tradeDiscountTotal);
return $coupon;

How can I create a bespoke discount for each order and ensure the products that are discounted are represented correctly in the admin area?

Upvotes: 1

Views: 1220

Answers (1)

7uc1f3r
7uc1f3r

Reputation: 29650

UPDATE

A solution is to create a coupon manually with a percentage discount with for example 10%. Then we add the following codes based on the couponcode

  1. First part to ensure that a discount of 0 is applied to products that meet the condition
  2. Second part to ensure that the coupon is automatically added to the shopping cart

So we get:

  • Discount amount on trade_discount_exempt = 0
function filter_woocommerce_coupon_get_discount_amount( $discount, $price_to_discount , $cart_item, $single, $coupon ) {
    // Product ID in cart
    $product_id = $cart_item['product_id'];
    
    // If 'trade_discount_exempt'
    if ( get_field( 'trade_discount_exempt', $product_id ) ) {
        $discount = 0;
    }

    return $discount;
}
add_filter( 'woocommerce_coupon_get_discount_amount', 'filter_woocommerce_coupon_get_discount_amount', 10, 5 );
  • Apply coupon programmatically if NOT trade_discount_exempt in cart
function action_woocommerce_before_calculate_totals( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

   if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;

    // Only cart
    if( ! is_cart() )
        return;

    // Coupon code
    $coupon_code = 'testcoupon';
    
    // Format
    $coupon_code = wc_format_coupon_code( $coupon_code );
    
    // Iterating though each cart items
    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        // Product ID in cart
        $product_id = $cart_item['product_id'];
      
        // NOT 'trade_discount_exempt'
        if ( ! get_field( 'trade_discount_exempt', $product_id ) ) {
            // Applied coupons
            $applied_coupons = $cart->get_applied_coupons();

            // Is applied
            $is_applied = in_array( $coupon_code, $applied_coupons );

            // NOT applied
            if ( ! $is_applied ) {
                // Apply
                $cart->apply_coupon( $coupon_code );
                break;
            }
        }
    }
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );


Optional: Here are 2 other possible solutions:

1. Use the woocommerce_calculated_total filter hook, apply a discount globally on cart

function filter_woocommerce_calculated_total( $total, $cart ) {
    // Discount (percentage)
    $percentage = 10; // 10 %
    
    // Set variable, used in loop
    $new_total = 0;
    
    // Iterating though each cart items
    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        // Product ID in cart
        $product_id = $cart_item['product_id'];

        // NOT 'trade_discount_exempt'
        if( ! get_field( 'trade_discount_exempt', $product_id ) ) {
            // Product price
            $price = $cart_item['data']->get_price();

            // Caclulate new price
            $new_price = $price * ( 1 - ( $percentage / 100 ) ); 

            // Add new price to new total
            $new_total += $new_price;
        }
    }
    
    // New total greater than
    if ( $new_total > 0 ) {
        $total = $new_total;
    }

    return $total;
}
add_filter( 'woocommerce_calculated_total', 'filter_woocommerce_calculated_total', 10, 2 );

2. Use the woocommerce_before_calculate_totals action hook, grant the discount on the product price

function action_woocommerce_before_calculate_totals( $cart ) {  
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
        return;
    
    // Discount (percentage)
    $percentage = 10; // 10 %
    
    // Iterating though each cart items
    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        // Product ID in cart
        $product_id = $cart_item['product_id'];
        
        // NOT 'trade_discount_exempt'
        if( ! get_field( 'trade_discount_exempt', $product_id ) ) {
            // Product price
            $price = $cart_item['data']->get_price();
            
            // Caclulate new price
            $new_price = $price * ( 1 - ( $percentage / 100 ) ); 

            // Set price
            $cart_item['data']->set_price( $new_price );
        }
    }
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );

Upvotes: 1

Related Questions