Woocommerce Add Coupon Based on Cart Subtotal - woocommerce

I am trying to add one of three coupons to the cart automatically based on the cart subtotal ($250 or more; $150-249.99; and $75-149.99). This is what I have, but it makes the cart just spin when you update an item quantity in the cart. It seems to work when an additional new item is added to the cart or when an item in the cart is removed. However, when I increased the quantity of one item to move from the smallest discount to the medium discount, the cart page didn't load at all (it was blank). It was still blank even after I went and added a new product to the cart. I had to comment out the action to get it to load the cart.
I'd appreciate any help.
This works, except that when the cart is updated, it just spins. If you refresh, the correct discount displays (and the item count that was changed was updated.) Any idea why it would just spin like this?
add_action( 'woocommerce_before_calculate_totals', 'sbs_auto_add_coupons_total_based', 10, 1 );
function sbs_auto_add_coupons_total_based( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$coupon_15 = 'dicount15';
$coupon_10 = 'discount10';
$coupon_5 = 'discount5';
$applied_coupons = $cart->get_applied_coupons();
$subtotal = 0;
foreach( $cart->get_cart() as $cart_item ) {
$subtotal += $cart_item['line_subtotal'];
}
if( $subtotal >= 250 && ! in_array($coupon_15, $applied_coupons ) ){
if( in_array($coupon_10, $applied_coupons ) )
$cart->remove_coupon( $coupon_10 );
if( in_array($coupon_5, $applied_coupons ) )
$cart->remove_discount($coupon_5);
$cart->add_discount( $coupon_15 );
}
elseif( $subtotal >= 150 && ! in_array($coupon_10, $applied_coupons ) ) {
if( in_array($coupon_15, $applied_coupons ) )
$cart->remove_coupon( $coupon_15 );
if( in_array($coupon_5, $applied_coupons ) )
$cart->remove_discount($coupon_5);
$cart->add_discount( $coupon_15 );
}
elseif( $subtotal >= 75 && ! in_array($coupon_5, $applied_coupons ) ) {
if( in_array($coupon_15, $applied_coupons ) )
$cart->remove_coupon( $coupon_15 );
if( in_array($coupon_10, $applied_coupons ) )
$cart->remove_discount($coupon_10);
$cart->add_discount( $coupon_5 );
}
else {
if( in_array($coupon_15, $applied_coupons ) )
$cart->remove_coupon( $coupon_15 );
if( in_array($coupon_10, $applied_coupons ) )
$cart->remove_discount($coupon_10);
if( in_array($coupon_5, applied_coupons ) )
$cart->remove_discount($coupon_5);
}
}

/**
Add Coupon Based on Cart Subtotal
*/
add_action( 'woocommerce_before_cart', 'add_coupon_automatically' );
function add_coupon_automatically() {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// HERE define your subtotal
$subtotal = 100;
// HERE define your coupon code
$coupon_code = '10off';
// HERE define your coupon amount
$coupon_amount = 10;
// HERE define your coupon discount type
$discount_type = 'percent';
// HERE define your coupon description
$coupon_description = '10% off for orders over $100';
// The active coupons
$active_coupons = WC()->cart->get_coupons();
// The cart subtotal
$cart_subtotal = WC()->cart->subtotal;
// If the cart subtotal is greater than $subtotal and the coupon is not already applied
if( $cart_subtotal >= $subtotal && ! isset($active_coupons[$coupon_code]) ) {
// Add the coupon
WC()->cart->add_discount( $coupon_code );
// Display a custom notice
wc_print_notice(
sprintf( '<strong>%s</strong> coupon has been applied!', $coupon_amount . '%' ), 'notice'
);
}
}

Related

Discount by shipping zone

On Woocommerce, I am trying to apply a coupon based on a specific shipping zone.
There is two shipping zone set:
the coupon should be used for the shipping zone germany ( shipping&zone_id=8 ). Not for all other shipping zones.
I have already tested a snippet that always shows me the coupon. Unfortunately I'm bad at programming.
`// Add / remove coupon based on cosen shipping
add_action( 'woocommerce_before_calculate_totals', 'adding_removing_coupon_shipping_based' );
function adding_removing_coupon_shipping_based( $cart ) {
if (is_admin() && !defined('DOING_AJAX'))
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// HERE the specific coupon code
$coupon_code = 'pfand';
$coupon_code = wc_format_coupon_code( $coupon_code );
$chosen_shipping = WC()->session->get('chosen_shipping_methods')[0];
$applied_coupons = $cart->get_applied_coupons();
$is_free = strpos( $chosen_shipping, 'deutschland' ) !== false;
$is_applied = in_array( $coupon_code, $applied_coupons );
if ( $is_applied && $is_free )
$cart->remove_coupon( $coupon_code );
elseif ( ! $is_applied && ! $is_free )
$cart->apply_coupon( $coupon_code );
}

Issue with changing WooCommerce cart item prices based on product meta

When the product subtotal is more than 3000, it has to be another price.
I added it as a meta field to products. On Stack Overflow, a long time ago someone advised me the filter for a special price called woocommerce_cart_item_name
I modified it a little for my purpose:
function kia_add_subtitle_to_cart_product( $title, $cart_item ){
$threshold = 3000; // Change price if > 3000
$_product = $cart_item['data'];
$meta = $_product->get_meta( '_opt_price_var');
$price = $_product->get_regular_price();
$subtotal = $cart_item['quantity'] * $price;
if ( $subtotal > $threshold && ( $meta )) {
$_product->set_price( $meta );
}
echo $title;
}
add_filter( 'woocommerce_cart_item_name', 'kia_add_subtitle_to_cart_product', 10, 2 );
The special price is showing only in the cart form, but not in cart totals and not in the checkout, in totals and in checkout the price is still regular, the main calculator doesn't take it from this filter.
How can I fix it? How to include it in the main calculator too?
I tried different hooks that can be responsive for the calculator - both add_action and add_filter, with and without 10, 2 - it isn't it.
add_action('woocommerce_before_shipping_calculator', 'kia_add_subtitle_to_cart_product',10,2);
add_action('woocommerce_before_cart_totals', 'kia_add_subtitle_to_cart_product', 10, 2 );
The woocommerce_cart_item_name hook is being misused in your code attempt. A filter hook should always return something compared to the use of echo.
You should use the woocommerce_before_calculate_totals hook instead
So you get:
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// Change price if > 3000
$threshold = 3000;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get regular price
$price = $cart_item['data']->get_regular_price();
// Subtotal = Get quantity * price
$subtotal = $cart_item['quantity'] * $price;
// Greater than
if ( $subtotal > $threshold ) {
// Get meta
$meta = $cart_item['data']->get_meta( '_opt_price_var', true );
// NOT empty
if ( ! empty ( $meta ) ) {
// Set new price
$cart_item['data']->set_price( $meta );
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
add_filter('woocommerce_calculated_total', 'custom_calculated_total', 10, 2);
function custom_calculated_total($total, $cart_object) {
if (is_admin() && !defined('DOING_AJAX'))
return;
if (!WC()->cart->is_empty()):
foreach ($cart_object->cart_contents as $key => $cart_item) {
$meta = $cart_item['data']->get_meta('_opt_price_var');
if ($total >= 3000 && ( $meta )) {
$total = $meta;
}
}
endif;
return $total;
}

Add free product when a certain coupon is applied in WooCommerce

I can add a product to cart, when a certain coupon is used via the woocommerce_applied_coupon hook and the add_to_cart() function
add_action('woocommerce_applied_coupon', 'apply_product_on_coupon');
function apply_product_on_coupon( ) {
global $woocommerce;
$coupon_id = 'mybday';
$free_product_id = 131468;
if(in_array($coupon_id, $woocommerce->cart->get_applied_coupons())){
$woocommerce->cart->add_to_cart($free_product_id, 1);
}
}
My question: is there a way to also discount it to 0 in the same callback function?
Your current code contains some mistakes or could be optimized:
global $woocommerce can be replaced by WC()
$woocommerce->cart->get_applied_coupons() is not necessary, as the coupon that have been applied is passed to the callback function.
Instead, use the last available argument in WC_Cart::add_to_cart() method, which will allow you to add any custom cart item data. Then you will be able to get that data easily from the cart object.
So you get:
function action_woocommerce_applied_coupon( $coupon_code ) {
// Settings
$product_id = 131468;
$quantity = 1;
$free_price = 0;
$coupon_codes = array( 'coupon1', 'mybday' );
// Compare
if ( in_array( $coupon_code, $coupon_codes ) ) {
// Add product to cart
WC()->cart->add_to_cart( $product_id, $quantity, 0, array(), array( 'free_price' => $free_price ) );
}
}
add_action( 'woocommerce_applied_coupon', 'action_woocommerce_applied_coupon', 10, 1 );
// Set free price from custom cart item data
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// Loop through cart contents
foreach ( $cart->get_cart_contents() as $cart_item ) {
if ( isset( $cart_item['free_price'] ) ) {
$cart_item['data']->set_price( $cart_item['free_price'] );
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
Note: in addition to using woocommerce_applied_coupon, you must also use woocommerce_removed_coupon for when the coupon is removed, the product is removed as well
function action_woocommerce_removed_coupon( $coupon_code ) {
// Settings
$product_id = 131468;
$coupon_codes = array( 'coupon1', 'mybday' );
// Compare
if ( in_array( $coupon_code, $coupon_codes ) ) {
// Loop through cart contents
foreach ( WC()->cart->get_cart_contents() as $cart_item_key => $cart_item ) {
// When product in cart
if ( $cart_item['product_id'] == $product_id ) {
// Remove cart item
WC()->cart->remove_cart_item( $cart_item_key );
break;
}
}
}
}
add_action( 'woocommerce_removed_coupon', 'action_woocommerce_removed_coupon', 10, 1 );

Add the values of product meta as fee in WooCommerce cart

In Italy there is a specific fee for the disposal of electronic products that must be paid during the purchase.
This "ecofee" is specific for each product.
I have set up a specific meta for each product called meta_product_grossecofee
I'd like to convert the value of this meta field in a fee on the cart.
This is the code I've tried, however without the desired result. Any advice?
add_action( 'woocommerce_cart_calculate_fees', 'ecofee_display' );
function ecofee_display(){
global $product;
$ecofee = $product->get_meta('meta_product_grossecofee');
if ($ecofee) {
WC()->cart->add_fee(__('Ecofee: ', 'txtdomain'), $ecofee);
}
}
The cart can contain multiple products, so global $product is not applicable here.
Instead, you can go through the cart and for each product for which the meta exists, add the value for this to the fee.
If the $fee is greater than 0, you can then apply it.
So you get:
function action_woocommerce_cart_calculate_fees( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Initialize
$fee = 0;
// Loop through cart contents
foreach ( $cart->get_cart_contents() as $cart_item ) {
// Get meta
$ecofee = $cart_item['data']->get_meta( 'meta_product_grossecofee', true );
// NOT empty & variable is a number
if ( ! empty ( $ecofee ) && is_numeric( $ecofee ) ) {
// Addition
$fee += $ecofee;
}
}
// If greater than 0
if ( $fee > 0 ) {
// Add additional fee (total)
$cart->add_fee( __( 'Ecofee', 'woocommerce' ), $fee, false );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );
Note: if you want to take into account the quantity per product:
Replace
// NOT empty & variable is a number
if ( ! empty ( $ecofee ) && is_numeric( $ecofee ) ) {
// Addition
$fee += $ecofee;
}
With
// NOT empty & variable is a number
if ( ! empty ( $ecofee ) && is_numeric( $ecofee ) ) {
// Get product quantity in cart
$quantity = $cart_item['quantity'];
// Addition
$fee += $ecofee * $quantity;
}

Auto apply coupon based on WooCommerce cart subtotal in which certain products are excluded

I am using the following code to auto apply a coupon when customer has $100 or more in cart.
add_action( 'woocommerce_checkout_before_order_review' , 'add_coupon_notice' );
function add_coupon_notice() {
$cart_total = WC()->cart->get_subtotal();
$minimum_amount = 100;
$currency_code = get_woocommerce_currency();
wc_clear_notices();
if ( $cart_total < $minimum_amount ) {
WC()->cart->remove_coupon( '20OFF100' );
wc_print_notice( "Get 20% off if you spend more than $$minimum_amount", 'notice' );
} else {
WC()->cart->apply_coupon( '20OFF100' );
wc_print_notice( '20% off $100 or more - Discount Applied!', 'notice' );
}
wc_clear_notices();
}
However, I want to exclude a specific product from this $100 minimum.
The specific product is on sale, and I've checked "Exclude Sale Items" in the coupon admin screen, but the code below is ignoring that.
Why isn't the 'Exclude Sale Items' working, and/or how can I go about this?
The biggest misconception in your code is that even though you checked "Exclude sale items" in the coupon admin screen, that the use of WC()->cart->get_subtotal() does not take this into account.
The solution:
You can use the woocommerce_before_calculate_totals hook
To avoid problems, use a coupon code without capital letters
When going through the cart content, we keep track of the total, except for the excluded products
Based on the current amount threshold and whether or not the coupon code has already been applied, we will display notices
So you get:
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// Coupon code
$coupon_code = 'coupon1';
// Total amount threshold
$amount_threshold = 100;
// Targeted product IDs, several can be entered, separated by a comma
$targeted_product_ids = array( 30, 813 );
// Initializing variables
$total_amount = 0;
$applied_coupons = $cart->get_applied_coupons();
// Loop through cart contents
foreach( $cart->get_cart_contents() as $cart_item ) {
// Excluding targeted product IDs
if ( ! in_array( $cart_item['data']->get_id(), $targeted_product_ids ) ) {
// Get the cart total amount
$total_amount += $cart_item['line_total'] + $cart_item['line_tax'];
}
}
// Applying coupon
if ( ! in_array( $coupon_code, $applied_coupons ) && $total_amount >= $amount_threshold ) {
$cart->apply_coupon( $coupon_code );
wc_clear_notices();
wc_add_notice( __( 'Succeeded', 'woocommerce' ), 'notice' );
}
// Buy more
elseif ( ! in_array( $coupon_code, $applied_coupons ) && $total_amount < $amount_threshold ) {
wc_clear_notices();
wc_add_notice( __( 'Buy more', 'woocommerce' ), 'notice' );
}
// Removing coupon
elseif ( in_array( $coupon_code, $applied_coupons ) && $total_amount < $amount_threshold ) {
$cart->remove_coupon( $coupon_code );
wc_clear_notices();
wc_add_notice( __( 'Removed', 'woocommerce' ), 'notice' );
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );

Resources