Search code examples
wordpresswoocommercecategoriescart

Discount for a specific product category in WooCommerce cart based on quantity and multiples


The discount I currently have essentially says

  • If 6 products within a specific category are in the cart --- discount the total price of $10

This piece of the code works fine. My issue is, this does not work

  • If there are 7 products, the 7th product being from a different category.

My goal is to give the discount no matter how many products are in the cart so long as there are 6 products within "Category A".

The following code works so long as there is 6 products in the "discounted category" or there is 1 product with a quantity of 6 etc. It falls apart when I add a product from another category. Feel free to rip it apart.

add_action( 'woocommerce_before_calculate_totals', 'this_item_free' );

function this_item_free() {

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

    $valid_product_category_id = array('soup-mix');
    $has_category = false;

    $count = WC()->cart->get_cart_contents_count();

    foreach ( WC()->cart->get_cart() as $product ) {
        $quantity = $product['quantity'];
        $price = $product['data']->get_price();
    }

    if ( has_term( $valid_product_category_id, 'product_cat', $product['product_id'],
            $product['quantity'] ) ) {
        $has_category = true;
        $cart_total = floatval( preg_replace( '#[^\d.]#', '', WC()->cart->get_cart_total() ) );

        if($count == 6 && $has_category = true){
            add_action( 'woocommerce_cart_calculate_fees', 'discount_based_on_total', 25, 1 );
            function discount_based_on_total( $cart ) {

                $total = $cart->cart_contents_total;
                $discount = 9.95;

                $cart->add_fee( __('discount', 'woocommerce'), -$discount );
                wc_add_notice( apply_filters( 'discount_applied', 'You just got a free soup!') );

            }
        }
    }
}

Solution

  • Your code contains some unnecessary steps and what you want to achieve can be obtained with just the woocommerce_cart_calculate_fees action hook

    My answer contains:

    Give a discount no matter how many products are in the cart so long as there are 6 products or there is 1 product with a quantity of 6, etc.. within "Category A".

    function action_woocommerce_cart_calculate_fees( $cart ) {
        if ( is_admin() && ! defined( 'DOING_AJAX' ) )
            return;
    
        /* SETTINGS */
    
        // Specific categories
        $specific_categories = array( 'Categorie-A' );
    
        // Discount
        $discount = 10;
        
        // Min quantity
        $minimun_quantity = 6;
    
        /* END SETTINGS */
        
        // Counter
        $current_quantity = 0;
    
        // Loop though each cart item
        foreach ( $cart->get_cart() as $cart_item ) {
            // Get product id
            $product_id = $cart_item['product_id'];
    
            // Has certain category     
            if ( has_term( $specific_categories, 'product_cat', $product_id ) ) {
                // Quantity
                $product_quantity = $cart_item['quantity'];
    
                // Add to total
                $current_quantity += $product_quantity;
            }
        }
    
        // Greater than or equal to
        if ( $current_quantity >= $minimun_quantity ) {          
            // Add fee
            $cart->add_fee( __( 'Discount_applied', 'woocommerce' ), -$discount, false );      
        }
    }
    add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );
    

    To apply the discount per 6 products (6 = $10, 12 = $20, 18 = $30, etc..)

    Replace

    // Greater than or equal to
    if ( $current_quantity >= $minimun_quantity ) {          
        // Add fee
        $cart->add_fee( __( 'Discount_applied', 'woocommerce' ), -$discount, false );      
    }
    

    With

    // Greater than or equal to
    if ( $current_quantity >= $minimun_quantity ) {
        // Modulo
        $mod = $current_quantity % $minimun_quantity;
        
        // Times it fit
        $times = ( $current_quantity - $mod ) / $minimun_quantity;
    
        // Discount * times
        $discount = $discount * $times;
        
        // Add fee
        $cart->add_fee( __( 'Discount_applied', 'woocommerce' ), -$discount, false );      
    }