Hello this code creates two discount classes, and then with a filter on the cart page it shows the regular price and the discounted price, how can I do to have the same visual result also on the mini cart??
this is what i am trying to achieve in the minicart
add_action( 'woocommerce_before_calculate_totals', 'bbloomer_quantity_based_pricing', 9999 );
function bbloomer_quantity_based_pricing( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// Define discount rules and thresholds
$threshold1 = 2; // Change price if items > 100
$discount1 = 0.05; // Reduce unit price by 5%
$threshold2 = 3; // Change price if items > 1000
$discount2 = 0.1; // Reduce unit price by 10%
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item )
{
if( has_term( array('cartucce-inkjet'), 'product_cat', $cart_item['product_id'] ) ){
if ( $cart_item['quantity'] >= $threshold1 && $cart_item['quantity'] < $threshold2 )
{
$price = round( $cart_item['data']->get_price() * ( 1 - $discount1 ), 2 );
$cart_item['data']->set_price( $price );
}
elseif ( $cart_item['quantity'] >= $threshold2 )
{
$price = round( $cart_item['data']->get_price() * ( 1 - $discount2 ), 2 );
$cart_item['data']->set_price( $price );
}
}
}
}
function filter_woocommerce_cart_item_price( $price_html, $cart_item, $cart_item_key ) {
// Get the product object
$product = $cart_item['data'];
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Get reqular price
$regular_price = $product->get_regular_price();
// New price
$new_price = $cart_item['data']->get_price();
// NOT empty and NOT equal
if ( ! empty ( $regular_price ) && $regular_price != $new_price ) {
// Output
$price_html = '<del>' . wc_price( $regular_price ) . '</del> <ins>' . wc_price( $new_price ) . '</ins>';
}
}
return $price_html;
}
add_filter( 'woocommerce_cart_item_price', 'filter_woocommerce_cart_item_price', 10, 3 );
Related
I'm trying to add a 10% discount to all products that fall into category B when a product from category A is in the cart, this is what i've tried so far and from what I see there's not an obvious reason but the discount is not applied in the cart. It can be a total discount fee or a separate discount for each item.
add_action( 'woocommerce_before_calculate_totals', 'apply_category_discount_in_cart', 10, 1 );
function apply_category_discount_in_cart( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$discount_amount = 0;
$category_A_in_cart = false;
// Loop through each item in the cart
foreach ( $cart->get_cart() as $cart_item ) {
$product = $cart_item['data'];
// Check if the product has category A
if ( has_term( 'categorya', 'product_cat', $product->get_id() ) ) {
$category_A_in_cart = true;
break;
}
}
// If a product with category A is found in the cart
if ( $category_A_in_cart ) {
// Loop through each item in the cart again
foreach ( $cart->get_cart() as $cart_item ) {
$product = $cart_item['data'];
// Check if the product has category B
if ( has_term( 'categoryb', 'product_cat', $product->get_id() ) ) {
$discount_amount += $cart_item['line_total'] * 0.1;
$cart_item['data']->set_price( $cart_item['data']->get_price() * 0.9 );
}
}
// Add the discount amount as a fee
$cart->add_fee( 'Discount', -$discount_amount, true );
}
}
I need to remove / disable the coupon effect for products discounted by more than 10%.
At the moment I have something like this:
function action_woocommerce_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// Specific categories: the term name/term_id/slug. Several could be added, separated by a comma
$excluded_categories = array( 'prod_category_name' );
// Initialize
$coupon_flag = false;
// Loop through applied coupons
foreach ( $cart->get_applied_coupons() as $coupon_code ) {
// Get an instance of the WC_Coupon Object
$coupon = new WC_Coupon( $coupon_code );
// Only for certain types, several can be added, separated by a comma
if ( in_array( $coupon->get_discount_type(), array( 'percent', 'percent_product' ) ) ) {
$coupon_flag = true;
break;
}
}
foreach( $cart->get_applied_coupons() as $coupon_code ) {
// Get the WC_Coupon object
$coupon = new WC_Coupon($coupon_code);
$coupon_amount = $coupon->get_amount(); // Get coupon amount
}
if ( $coupon_flag ) {
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get product ID in
$product_id = $cart_item['product_id'];
// NOT contains the definite term
if ( ! has_term( $excluded_categories, 'product_cat', $product_id ) ) {
// Get regular price
$regular_price = $cart_item['data']->get_regular_price();
// Get promo price
$promo_price = $cart_item['data']->get_price();
// Zniżka
$discount = 100 - (($promo_price * 100) / $regular_price);
$percentage = 10;
$percent_price = $regular_price - ($regular_price * ($percentage / 100));
if ($discount > $coupon_amount ) {
//$coupon->set_amount(0);
$cart->remove_coupon( 'coupon_name' );
}
if ( $percent_price < $promo_price ) {
$cart_item['data']->set_price( $regular_price );
} else {
$cart_item['data']->set_price( $promo_price );
}
}
}
}
}
At the moment, the code removes the coupon for the entire cart:
$cart->remove_coupon( 'coupon_name' );
Is there an option to remove the discount for the selected product from the cart?
I need something like:
$cart_item['data']->remove_coupon( 'coupon_name' );
Thank you so much!
Ok I added filter and it works perfect =)
add_filter( 'woocommerce_coupon_is_valid_for_product', 'exclude_product_from_product_promotions_frontend', 9999, 4 );
function exclude_product_from_product_promotions_frontend( $valid, $product, $coupon, $values ) {
$regular_price = $product->get_regular_price();
$promo_price = $product->get_price();
$discount = 100 - (($promo_price * 100) / $regular_price);
$coupon_amount = 10;
if ($discount > $coupon_amount ) {
$valid = false;
}
return $valid;
}
When a coupon is applied (belonging to a certain type) I change the product discount price to the regular price via:
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 10, 1);
function add_custom_price( $cart_object) {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$coupon = False;
if ($coupons = WC()->cart->get_applied_coupons() == False )
$coupon = False;
else {
foreach ( WC()->cart->get_applied_coupons() as $code ) {
$coupons1 = new WC_Coupon( $code );
if ($coupons1->type == 'percent_product' || $coupons1->type == 'percent')
$coupon = True;
}
}
if ($coupon == True)
foreach ( $cart_object->get_cart() as $cart_item )
{
$price = $cart_item['data']->regular_price;
$cart_item['data']->set_price( $price );
}
}
But if I have a category excluded, the code freaks out because it changes the price from sale to regular in the cart and does not add a discount.
How to work around this so that the excluded category does not change to the regular price?
To exclude certain categories you can use has_term() when loop through the cart items
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;
// Specific categories: the term name/term_id/slug. Several could be added, separated by a comma
$excluded_categories = array( 63, 15, 'categorie-1' );
// Initialize
$coupon_flag = false;
// Loop through applied coupons
foreach ( $cart->get_applied_coupons() as $coupon_code ) {
// Get an instance of the WC_Coupon Object
$coupon = new WC_Coupon( $coupon_code );
// Only for certain types, several can be added, separated by a comma
if ( in_array( $coupon->get_discount_type(), array( 'percent', 'percent_product' ) ) ) {
$coupon_flag = true;
break;
}
}
// True
if ( $coupon_flag ) {
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get product ID in
$product_id = $cart_item['product_id'];
// NOT contains the definite term
if ( ! has_term( $excluded_categories, 'product_cat', $product_id ) ) {
// Get regular price
$regular_price = $cart_item['data']->get_regular_price();
// Set new price
$cart_item['data']->set_price( $regular_price );
}
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'action_woocommerce_before_calculate_totals', 10, 1 );
the following code: Set product sale price programmatically in WooCommerce 3 works perfectly.
Also its continuation: Set programmatically product sale price and cart item prices in Woocommerce 3.
However I'd like to exclude an user role from this function altogether, how can I do that?
I added the following to the code above to no avail:
if ( ! wc_current_user_has_role( 'trader' ) ) return $product->get_regular_price();
Thanks
After asking around and trying it out, the following code manages to achieve what I need. For future reference if someone else needs it:
// Generating dynamically the product "regular price"
add_filter( 'woocommerce_product_get_regular_price', 'custom_dynamic_regular_price', 10, 2 );
add_filter( 'woocommerce_product_variation_get_regular_price', 'custom_dynamic_regular_price', 10, 2 );
function custom_dynamic_regular_price( $regular_price, $product ) {
if( empty($regular_price) || $regular_price == 0 )
return $product->get_price();
else
return $regular_price;
}
// Generating dynamically the product "sale price"
add_filter( 'woocommerce_product_get_sale_price', 'custom_dynamic_sale_price', 10, 2 );
add_filter( 'woocommerce_product_variation_get_sale_price', 'custom_dynamic_sale_price', 10, 2 );
function custom_dynamic_sale_price( $sale_price, $product ) {
$user = wp_get_current_user();
$rate = 0.9;
if( in_array( 'trader', (array) $user->roles ) ) {
return $product->get_regular_price() * $rate;
}
else
{
if( empty($sale_price) || $sale_price == 0 )
return $product->get_regular_price() * $rate;
else
return $sale_price;
}
};
// Displayed formatted regular price + sale price
add_filter( 'woocommerce_get_price_html', 'custom_dynamic_sale_price_html', 20, 2 );
function custom_dynamic_sale_price_html( $price_html, $product ) {
if( $product->is_type('variable') ) return $price_html;
$user = wp_get_current_user();
if( in_array( 'trader', (array) $user->roles ) ) {
$price_html = wc_price($product->get_regular_price() );
return $price_html;
}
else
{
$price_html = wc_format_sale_price( wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ), wc_get_price_to_display( $product, array( 'price' => $product->get_sale_price() ) ) ) . $product->get_price_suffix();
return $price_html;
}
}
add_action( 'woocommerce_before_calculate_totals', 'set_cart_item_sale_price', 20, 1 );
function set_cart_item_sale_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Iterate through each cart item
foreach( $cart->get_cart() as $cart_item ) {
$price = $cart_item['data']->get_sale_price(); // get sale price
$cart_item['data']->set_price( $price ); // Set the sale price
}
}
I'm adding the discount rule for every 3 products: 3,6,9,12,15.. on the cart and it should apply to discount 50% only the cheapest products.
So if you have 9, only the 3 cheapest gets 50% off.
This code applies a discount to all products, so it should only be every 3 products
add_action('woocommerce_cart_calculate_fees', 'ts_add_custom_discount', 10, 1 );
function ts_add_custom_discount( $wc_cart ){
$discount = 0;
$product_ids = array();
$item_prices = array();
$in_cart = false;
foreach ( $wc_cart->get_cart() as $cart_item_key => $cart_item ) {
$cart_product = $cart_item['data'];
if ( has_term( 'get2', 'product_cat', $cart_product->get_id() ) ) { // get2 selected category
$in_cart = true;
}else {
$in_cart = true;
$product_ids[] = $cart_product->get_id();
$item_prices[$cart_product->get_id()] = $cart_product->get_price();
}
}
if( $in_cart ) {
$count_ids = count($product_ids);
asort( $item_prices ); //Sort the prices from lowest to highest
$cartQuantity = WC()->cart->cart_contents_count;
$count = 0;
if( $count_ids > 3 || $cartQuantity >= 3 ) {
foreach( $item_prices as $id => $price ) {
if( $count >= 1 ) {
break;
}
//$product = wc_get_product( $id );
//$price = $product->get_price();
$discount -= ($price * 50) /100;
$count++;
}
}
}
if( $discount != 0 ){
$wc_cart->add_fee( 'Discount', $discount, true );
}
}
I have attached a screenshot, you can see there is a red outline for every 3rd cheapest product.
This answer will apply a 50% discount per 3 products on the cheapest products. (explanation via comment tags added to the code)
So you get:
function action_woocommerce_cart_calculate_fees( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
// Products in cart
$products_in_cart = count( $cart->get_cart() );
// Every so many products
$every = 3;
// When products in cart greater than or equal to every so many products
if ( $products_in_cart >= $every ) {
// Set array
$product_prices = array();
// Loop though cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Product
$product = $cart_item['data'];
// Get price
$product_price = $product->get_price();
// Push
$product_prices[] = $product_price;
}
// Sort: low to high
asort( $product_prices );
// Number of products receive a discount
$products_receive_discount = floor( $products_in_cart / $every );
// Set variable
$total = 0;
// Loop trough
foreach ( array_slice( $product_prices, 0, $products_receive_discount ) as $product_price ) {
// Calculate
$total += $product_price;
}
// Calculate discount
$discount = ( $total * 50 ) / 100;
// Discount
$cart->add_fee( __( 'Discount', 'woocommerce' ), -$discount, true );
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );