I use this code which gives customers a discount based in speific amount ranges that generates discount of 2% 4% 6% for regular buyers and 3% 5% 7% for customers with the role "vip".
The code must also exclude the categories I added. If a customer puts a product in the shopping cart that belongs to those products, it should not count with it/them. Right now it counts with them anyway and I can't get it to work.
The discount steps work as they should but not excluding products that are in the categories I specified to exclude. When i have example a green tshirt in it counts it and when i put one of the red excluded tshirts in it still counts it anyway even tough it shouldnt.
add_action( 'woocommerce_cart_calculate_fees', 'custom_discount_based_on_cart_total', 10, 1 );
function custom_discount_based_on_cart_total( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// excluding categories here
$excluded_categories = array( 'redshirt1', 'redshirt2', 'redshirt3', 'redshirt4' );
$discounted_total = 0;
foreach ( $cart->get_cart() as $cart_item ) {
$product = $cart_item['data'];
$product_id = $product->get_id();
$terms = get_the_terms( $product_id, 'product_cat' );
$exclude = false;
foreach ( $terms as $term ) {
if ( in_array( $term->slug, $excluded_categories ) ) {
$exclude = true;
break;
}
}
if ( ! $exclude ) {
$discounted_total += $cart_item['line_subtotal'];
}
}
$discount = 0;
$discount_text = "";
// check if the user is in the role 'vip'
$user = wp_get_current_user();
$is_customer = in_array( 'vip', (array) $user->roles );
if ( $discounted_total >= 2000 && $discounted_total < 4000 ) {
$discount = $discounted_total * ($is_customer ? 0.03 : 0.02); // 3% for vip, 2% for others
$discount_text = 'Discount ' . ($is_customer ? '3%' : '2%');
} else if ( $discounted_total >= 4000 && $discounted_total < 6000 ) {
$discount = $discounted_total * ($is_customer ? 0.05 : 0.04); // 5% for vip, 4% for others
$discount_text = 'Discount ' . ($is_customer ? '5%' : '4%');
} else if ( $discounted_total >= 6000 ) {
$discount = $discounted_total * ($is_customer ? 0.07 : 0.06); // 7% for vip, 6% for others
$discount_text = 'Discount ' . ($is_customer ? '7%' : '6%');
}
if ( $discount > 0 ) {
$cart->add_fee( __( $discount_text, 'woocommerce' ), -$discount );
}
}
add_action( 'woocommerce_before_cart', 'show_discount_message' );
function show_discount_message() {
$cart = WC()->cart;
$total = $cart->subtotal;
// excluding categories
$excluded_categories = array( 'redshirt1', 'redshirt2', 'redshirt3', 'redshirt4' );
$discounted_total = $total;
foreach ( $cart->get_cart() as $cart_item ) {
$product = $cart_item['data'];
$product_cats = wp_get_post_terms( $product->get_id(), 'product_cat' );
foreach ( $product_cats as $product_cat ) {
if ( in_array( $product_cat->slug, $excluded_categories ) ) {
$discounted_total -= $cart_item['line_subtotal'];
break;
}
}
}
// check if the user is in role 'vip'
$user = wp_get_current_user();
$is_customer = in_array( 'vip', (array) $user->roles );
$return_to = wc_get_page_permalink( 'shop' );
if ( $discounted_total < 2000 ) {
$difference = 2000 - $discounted_total;
$added_text = 'you have ' . wc_price( $difference ) . ' untill you reach level 1 (' . ($is_customer ? '3%' : '2%') . ') on the discount!';
$notice = sprintf( '<a href="%s" class="button wc-forward">%s</a> %s', esc_url( $return_to ), 'Keep shopping', $added_text );
wc_print_notice( $notice, 'notice' );
} else if ( $discounted_total >= 2000 && $discounted_total < 4000 ) {
$difference = 4000 - $discounted_total;
$added_text = 'you have ' . wc_price( $difference ) . ' untill you reach level 2 (' . ($is_customer ? '5%' : '4%') . ') on the discount!';
$notice = sprintf( '<a href="%s" class="button wc-forward">%s</a> %s', esc_url( $return_to ), 'Keep shopping', $added_text );
wc_print_notice( $notice, 'notice' );
} else if ( $discounted_total >= 4000 && $discounted_total < 6000 ) {
$difference = 6000 - $discounted_total;
$added_text = 'you have ' . wc_price( $difference ) . ' untill you reach level 3 (' . ($is_customer ? '7%' : '6%') . ') on the discount!';
$notice = sprintf( '<a href="%s" class="button wc-forward">%s</a> %s', esc_url( $return_to ), 'Keep shopping', $added_text );
wc_print_notice( $notice, 'notice' );
}
}
In WooCommerce product categories and tags are not handled by product variations, but by the parent variable product. So for variations cart items, you need to get the parent product ID to be able to target specific product categories. There was also some other mistakes.
Here is your revisited code:
// Custom conditional function for excluded product categories
function has_excluded_product_categories( $product ) {
// Set HERE your Excluded product categories (slugs)
$excl_terms = array( 'redshirt1', 'redshirt2', 'redshirt3', 'redshirt4', 'hoodies' );
// IMPORTANT!!!: Handling Product variations
$product_id = $product->get_parent_id() ? $product->get_parent_id() : $product->get_id();
// Simplifying: Get directly an array of product categories "slugs"
$term_slugs = wp_get_post_terms( $product_id, 'product_cat', array( 'fields' => 'slugs' ) );
// Using array_intersect() on 2 arrays instead of a heavier foreach loop
return (bool) count( array_intersect($term_slugs, $excl_terms) ) > 0;
}
// Adding a discount conditionally
add_action( 'woocommerce_cart_calculate_fees', 'custom_discount_based_on_cart_total', 10, 1 );
function custom_discount_based_on_cart_total( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Initializing variables
$discounted_total = 0;
$discount = 0;
$discount_text = __('Discount ', 'woocommerce');
foreach ( $cart->get_cart() as $cart_item ) {
if ( ! has_excluded_product_categories( $cart_item['data'] ) ) {
$discounted_total += $cart_item['line_subtotal']; // add item line subtotal
}
}
$user = wp_get_current_user();
$is_customer = in_array( 'vip', (array) $user->roles ); // check if the user is in the role 'vip'
if ( $discounted_total >= 2000 && $discounted_total < 4000 ) {
$discount = $discounted_total * ($is_customer ? 0.03 : 0.02); // 3% for vip, 2% for others
$discount_text .= $is_customer ? '3%' : '2%';
} else if ( $discounted_total >= 4000 && $discounted_total < 6000 ) {
$discount = $discounted_total * ($is_customer ? 0.05 : 0.04); // 5% for vip, 4% for others
$discount_text .= $is_customer ? '5%' : '4%';
} else if ( $discounted_total >= 6000 ) {
$discount = $discounted_total * ($is_customer ? 0.07 : 0.06); // 7% for vip, 6% for others
$discount_text .= $is_customer ? '7%' : '6%';
}
if ( $discount > 0 ) {
$cart->add_fee( $discount_text, -$discount );
}
}
// Display related discount message
add_action( 'woocommerce_before_cart', 'show_discount_message' );
function show_discount_message() {
$discounted_total = 0;
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( ! has_excluded_product_categories( $cart_item['data'] ) ) {
$discounted_total = $cart_item['line_subtotal']; // add item line subtotal
}
}
// check if the user is in role 'vip'
$user = wp_get_current_user();
$is_customer = in_array( 'vip', (array) $user->roles );
$level = 0;
$return_to = esc_url( wc_get_page_permalink( 'shop' ) );
if ( $discounted_total < 2000 ) {
$difference = 2000 - $discounted_total;
$level = 1;
$percentage = $is_customer ? '3%' : '2%';
} else if ( $discounted_total >= 2000 && $discounted_total < 4000 ) {
$difference = 4000 - $discounted_total;
$level = 2;
$percentage = $is_customer ? '5%' : '4%';
} else if ( $discounted_total >= 4000 && $discounted_total < 6000 ) {
$difference = 6000 - $discounted_total;
$level = 3;
$percentage = $is_customer ? '7%' : '6%';
}
if ( $level != 0 ) {
$added_text = sprintf( __('You have %s untill you reach level %d (%s) on the discount!', 'woocommerce'),
wc_price( $difference ), $level, $percentage );
wc_print_notice( sprintf( '<a href="%s" class="button wc-forward">%s</a> %s', $return_to,
__('Keep shopping', 'woocommerce'), $added_text ), 'notice' );
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Note: I didn't tested the "vip" user role