I am trying to apply a percentage discount based on quantity of products with a specific product attribute, in cart.
More precisely my goal is to apply 15% discount on orders of minimum 6 products with the attribute flaske
.
I have managed to achieve this for variable products with variation attributes set, but I can't seem to target the single/simple products.
My code so far (borrowed from Condition for Quantity and Price for Woocommerce):
// Discount based on product quantity and attribute in cart
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
$min_item_amount = 6; // Min quantity
$discount = $items_count = $percent = $items_subtotal = 0;
$taxonomy = 'pa_variant'; // Taxonomy
$term_slugs = array('flaske'); // Term/terms
// Loop through cart items
foreach( $cart->get_cart() as $cart_item_key => $cart_item ) {
// Loop through variation
foreach( $cart_item['variation'] as $attribute => $term_slug ) {
// Only counting items that are above 6 and has attribute
if( $cart_item['data']->get_price() >= $min_item_amount && $attribute === 'attribute_'.$taxonomy && in_array( $term_slug, $term_slugs ) ) {
$items_count += $cart_item['quantity'];
$items_subtotal += $cart_item['line_subtotal'];
}
}
}
// CONDITIONAL PERCENTAGE
if ($items_count >= 6 ) {
$percent = 15;
}
// DISCOUNT (TAXABLE)
if( $items_count > 0 ) {
// Calculation
$discount -= ($items_subtotal / 100) * $percent;
$cart->add_fee( __( "Mix & Match rabat - $percent%", "woocommerce" ), $discount, true);
}
}
My current code works very well for variable products (the variants), but it doesn't seem to affect single products, even if I give the single products the same attributes as the variable product.
I suspect it has to do with the foreach
loop foreach( $cart_item['variation'] as $attribute => $term_slug )
How can I make this work in general, so it also applies for single/simple products with same attribute flaske
?
Any help and advice would be appreciated.
Other useful references:
Woocommerce percentage discount per item based on quantity
Exclude variations with 2 specific attribute terms from coupon usage in Woocommerce
You don't get the product attributes set in simple or variable products, in the same way as for product variations.
The following revisited code should also handle simple products (untested):
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
// 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) {
// Only counting items that are above 6 and has attribute
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) {
$percent = 15;
}
// DISCOUNT (TAXABLE)
if ($items_count > 0) {
// Calculation
$discount -= ($items_subtotal / 100) * $percent;
$cart->add_fee(__("Mix & Match rabat - $percent%", "woocommerce"), $discount, true);
}
}
It should work.