1

I am trying to exclude any products where any coupon code is applied, from my custom discount code, on the checkout page.

In my code, I am applying a discount to the order when x amount of products are added to the cart, with a specific variation taxonomy. I am trying to make this code work, so no discount may be given on items where ANY coupon code is used.

The discount code should only apply on products where no other coupon code has been applied/is active.

add_action( 'woocommerce_cart_calculate_fees','wc_cart_item_quantity_discount' );
function wc_cart_item_quantity_discount( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    // INITIALIZING VARIABLES
    $discount = $items_count = $percent = $items_subtotal = 0;
    $taxonomy   = 'pa_variant'; // Taxonomy
    $term_slugs = array('flaske'); // Term/terms
    $couponcode = WC()->cart->get_applied_coupons(); // check for any coupon code

    // Loop through cart items
    foreach( $cart->get_cart() as $cart_item_key => $cart_item ) {
        $product = $cart_item['data'];
        // Product variations
        if( $product->is_type('variation') ) {
            // Loop through variation attributes
            foreach ($cart_item['variation'] as $attribute => $term_slug) {
                if ($attribute === 'attribute_' . $taxonomy && in_array($term_slug, $term_slugs)) {
                    $items_count += $cart_item['quantity'];
                    $items_subtotal += $cart_item['line_subtotal'];
                }
            }
        } 
        // Simple products
        elseif ( $product->is_type('simple') ) {
            $attributes = $product->get_attributes();

            if( ! empty($attributes) && array_key_exists($taxonomy, $attributes) ) {
                $terms = (array) $attributes[$taxonomy]->get_terms(); // array of WP_Term objects
                $slugs = array_map(function($term) { return $term->slug; }, $terms); // Extract only the term slugs

                if (count( array_intersect($slugs, $term_slugs) ) > 0 ) {
                    $items_count += $cart_item['quantity'];
                    $items_subtotal += $cart_item['line_subtotal'];
                }
            }
        }
    }
    // CONDITIONAL PERCENTAGE
    if ($items_count >= 6 && ! $couponcode ) { // CHECK COUPON
        $percent = 15;
    }
    // DISCOUNT (TAXABLE)
    if ($items_count > 0 ) {
        // Calculation
        $discount -= ($items_subtotal / 100) * $percent;
        $cart->add_fee(__("Mix & Match rabat - $percent%", "woocommerce"), $discount, true);
    }
}

What I have tried

I thought this could easily be done by checking if a coupon has been applied to cart, using WC()->cart->get_applied_coupons().

However, if ($items_count >= 6 && ! $couponcode ) { removes the discount completely when a coupon code is applied. I only want to exclude products with coupons active, from the discounted calculations.

Is there any way to achieve this?

Reference:

Check if a coupon is applied to cart in WooCommerce

Check if ANY coupon code is applied in WooCommerce

Remove one payment gateway if a coupon is applied

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
Richard
  • 61
  • 7

1 Answers1

1

You need something a bit different, optimized in a simpler way.

  • First, let replace the term slug by the term name and use the method get_attribute(), to target only specific cart items (works with simple products and product variations).
  • To target undiscounted cart items, the item subtotal need to be the same as the item total (so we don't need to check for applied coupons codes, as it doesn't work when a coupon has restrictions at product level).

So your code will be:

add_action( 'woocommerce_cart_calculate_fees', 'wc_cart_item_quantity_discount' );
function wc_cart_item_quantity_discount( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    $discount  = $items_count = $percent = $items_subtotal = 0; // Initializing variables
    $taxonomy  = 'pa_variant'; // Attribute taxonomy (or taxonomy label name too)
    $term_name = 'Flaske'; // Attribute term NAME

    // Loop through cart items
    foreach( $cart->get_cart() as $item ) {
        $product = $item['data'];

        // Targeting undiscounted items that have a specific product attribute value
        if ( $product->get_attribute($taxonomy) === $term_name 
        && $item['line_subtotal'] === $item['line_total'] ) {
            $items_count    += $item['quantity'];
            $items_subtotal += $item['line_subtotal'];
        }
    }
    // Discount percentage based on item count
    if ($items_count >= 6 ) { 
        $percent   = 15; // Discount percentage
        $discount -= $items_subtotal * $percent / 100; // Calculation
        $cart->add_fee( __('Mix & Match rabat', 'woocommerce') . " - {$percent}%", $discount );
    }
}

Code goes in functions.php file of your child theme (or in a plugin). Tested and works.

Note: Using a fee with a negative amount to get a discount, is a trick, and in this case, it is always taxable even if you set the $taxable argument as false.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • 1
    Hi @LoicTheAztec. Thank you for the prompt reply and also for correcting my question. The code is fully functional as is, because even the `$term_name` is correct in this specific case. – Richard Aug 08 '23 at 13:58