My WP site sells customized t-shirts. The customization plugin makes each customized shirt a line item in the woocommerce cart. If there are 2 shirts ordered of one design (quantity of 2 on that line item) I want to discount. But if there is just 1 item per line I dont want to discount.
I found this solution
Adding a discount by cart items conditionally based on the item quantity
But this seems to change the product price in the db, so after the discount kicks in for say 2 blue shirts because there were 2 ordered on 1 line, if I add a 3rd shirt on a separate line it also gets the discount, which I dont want.
Since woocommerce version 3+ the linked answer code doesn't work. It needs something different and can even be done in a better way.
The code will apply a cart item discount based on the cart item quantity. In this code example, it will apply a discount of 5% on the cart item, when the quatity is equal or more than 2 (two).
The cart item unit price displayed is always the real product price. The discount will be effective and displayed on the cart item subtotal.
Additionally the product name will be appended with a discount mention.
The code:
add_filter('woocommerce_add_cart_item_data', 'add_items_default_price_as_custom_data', 20, 3 );
function add_items_default_price_as_custom_data( $cart_item_data, $product_id, $variation_id ){
$product_id = $variation_id > 0 ? $variation_id : $product_id;
## ----- YOUR SETTING ----- ##
$discount_percentage = 5; // Discount (5%)
// The WC_Product Object
$product = wc_get_product($product_id);
// Only for non on sale products
if( ! $product->is_on_sale() ){
$price = (float) $product->get_price();
// Set the Product default base price as custom cart item data
$cart_item_data['base_price'] = $price;
// Set the Product discounted price as custom cart item data
$cart_item_data['new_price'] = $price * (100 - $discount_percentage) / 100;
// Set the percentage as custom cart item data
$cart_item_data['percentage'] = $discount_percentage;
}
return $cart_item_data;
}
// Display the product original price
add_filter('woocommerce_cart_item_price', 'display_cart_items_default_price', 20, 3 );
function display_cart_items_default_price( $product_price, $cart_item, $cart_item_key ){
if( isset($cart_item['base_price']) ) {
$product = $cart_item['data'];
$product_price = wc_price( wc_get_price_to_display( $product, array( 'price' => $cart_item['base_price'] ) ) );
}
return $product_price;
}
// Display the product name with the discount percentage
add_filter( 'woocommerce_cart_item_name', 'append_percetage_to_item_name', 20, 3 );
function append_percetage_to_item_name( $product_name, $cart_item, $cart_item_key ){
if( isset($cart_item['percentage']) && isset($cart_item['base_price']) ) {
if( $cart_item['data']->get_price() != $cart_item['base_price'] )
$product_name .= ' <em>(' . $cart_item['percentage'] . '% discounted)</em>';
}
return $product_name;
}
add_action( 'woocommerce_before_calculate_totals', 'custom_discounted_cart_item_price', 20, 1 );
function custom_discounted_cart_item_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
## ----- YOUR SETTING ----- ##
$targeted_qty = 2; // Targeted quantity
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// For item quantity of 2 or more
if( $cart_item['quantity'] >= $targeted_qty && isset($cart_item['new_price']) ){
// Set cart item discounted price
$cart_item['data']->set_price($cart_item['new_price']);
}
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
To display the discounted product price instead of the original product price, just remove woocommerce_cart_item_price() function (and hook)…
Newest similar: Cart item quantity progressive percentage discount in Woocommerce 3
Related
I have set up my cart to display the product price with a strikethrough next to the sale price of the discounted item (see first product in cart in photo).
checkout screenshot
This was achieved using this code
function my_custom_show_sale_price_at_cart( $old_display, $cart_item, $cart_item_key ) {
$product = $cart_item['data'];
if ( $product ) {
return $product->get_price_html();
}
return $old_display;
}
add_filter( 'woocommerce_cart_item_price', 'my_custom_show_sale_price_at_cart', 10, 3 );
The issue as you can see in the photo is that this only works for products on sale (the $12.00 product on sale for 0.00). However, a coupon code is applied to the other two items.
I followed this thread to display the total savings as "You Saved" in the checkout summary, including sale and coupon discounts.
How can I display the discounted price of the items in the cart that have the coupon applied to them?
So this will update the cart item totals and the line item totals based on what I interpreted your comments to be.
This would be added to functions.php
function my_custom_show_sale_price_at_cart( $old_display, $cart_item, $cart_item_key ) {
$product = $cart_item['data'];
// If you just want this to show in checkout vs cart + checkout - add && is_checkout() below.
if ( $product ) {
// This item has a coupon applied.
if ( floatval( $product->get_price() ) !== number_format( $cart_item['line_total'], 2 ) / $cart_item['quantity'] ) {
// This updates the item total.
$price_html = wc_format_sale_price( $product->get_regular_price(), number_format( $cart_item['line_total'], 2 ) ) . $product->get_price_suffix();
} else {
$price_html = $product->get_price_html();
}
// This updates the line item sub-total.
add_filter(
'woocommerce_cart_item_subtotal',
function() use ( $cart_item ) {
return wc_price( $cart_item['line_total'] + $cart_item['line_tax'] );
}
);
return $price_html;
}
return $old_display;
}
add_filter( 'woocommerce_cart_item_price', 'my_custom_show_sale_price_at_cart', 10, 3 );
I would like to replicate promo for a specific item.
If you buy one (b10 plus) product then you're eligible for a total 289€ discount on all light shaping tools, so if you add to cart accessories for a "category subtotal" of 100€ you get 100€ discount, if you take 300€ accessories you get 289€ discount.
I tried with another solution (plugins and php code) but it keeps discounting each item (that correspond to "accessories") for $289.
I also tried to include automatically a discount for that category if the "B10 plus" is in the cart. but this code add the discount to single products
This is my current code:
add_action( 'woocommerce_before_cart', 'bbloomer_apply_matched_coupons' );
function bbloomer_apply_matched_coupons() {
$coupon_code = 'promob10';
if ( WC()->cart->has_discount( $coupon_code ) ) return;
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
// this is your product ID
$autocoupon = array( 373 );
if ( in_array( $cart_item['product_id'], $autocoupon ) ) {
WC()->cart->apply_coupon( $coupon_code );
wc_print_notices();
}
}
}
To apply a discount based on a specific product ID you can use the woocommerce_cart_calculate_fees hook
First of all you will have to determine the specific product ID, this corresponds to the b10 product from your question
Then it will be checked whether this specific product is in the cart via find_product_in_cart(). If that's the case, let's move on
Through the price of the specific product ID, we determine the maximum discount
The price of the products belonging to the particular category is added to total discount (assuming that the b10 product does not belong to this category)
If the total discount is less than the maximum discount, we will use this discount. If not, the maximum discount will be applied
So you get:
function action_woocommerce_cart_calculate_fees( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Product ID of the specific product
$specific_product_id = 817;
// The term name/term_id/slug to check for.
$category = 'accessories';
// Initialize
$total_discount = 0;
$maximum_discount = 0;
// Cart id
$product_cart_id = $cart->generate_cart_id( $specific_product_id );
// Find product in cart
$in_cart = $cart->find_product_in_cart( $product_cart_id );
// In cart
if ( $in_cart ) {
// Gets cart contents
foreach ( $cart->get_cart_contents() as $cart_item ) {
// Get product id
$product_id = $cart_item['product_id'];
// Compare
if ( $product_id == $specific_product_id ) {
// Get price = maximum discount
$maximum_discount = $cart_item['data']->get_price();
}
// Has certain category
if ( has_term( $category, 'product_cat', $product_id ) ) {
// Get price
$price = $cart_item['data']->get_price();
// Get quantity
$quantity = $cart_item['quantity'];
// Addition to the total discount
$total_discount += $price * $quantity;
}
}
// Less than
if ( $total_discount < $maximum_discount ) {
// Add total discount
$cart->add_fee( __( 'Discount applied', 'woocommerce' ), -$total_discount, false );
} else {
// Add maximum discount
$cart->add_fee( __( 'Discount applied', 'woocommerce' ), -$maximum_discount, false );
}
}
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );
In woocommerce I am trying to make a custom cart item quantity discount for a specific product ID only. This is what I am trying to do:
If a customer add to cart a specific product, I would like to keep the original price for the first item and set a discounted custom price for each additional item quantity.
For example:
The product active price is 40 (we keep this price for 1st quantity item)
For quantities up to 2 (additional items quantity) the price is 12.
So if customer add the product with a quantity 5 items, then the price will be:
40 + 12 + 12 + 12 + 12 = 88
So I tried changing this answer code a bit:
Cart item quantity progressive percentage discount in Woocommerce 3
But couldn't make it work correctly.
Any help is appreciated.
For your case use the following instead:
add_filter('woocommerce_add_cart_item_data', 'add_items_default_price_as_custom_data', 20, 3 );
function add_items_default_price_as_custom_data( $cart_item_data, $product_id, $variation_id ){
## Your settings her below ##
$product_ids = array(37); // <=== Your specific product(s) ID(s) in the array
$discounted_price = 12; // <=== The specific product discounted price
// The WC_Product Object
$product = wc_get_product($variation_id > 0 ? $variation_id : $product_id);
if( array_intersect( $product_ids, array($product_id, $variation_id) ) && ! $product->is_on_sale() ){
// We set the Product discounted price
$cart_item_data['pricing']['discounted'] = $discounted_price;
// Set the Product default base price as custom cart item data
$cart_item_data['pricing']['active'] = $product->get_price();
}
return $cart_item_data;
}
// Display the product original price
add_filter('woocommerce_cart_item_price', 'display_cart_items_default_price', 20, 3 );
function display_cart_items_default_price( $product_price, $cart_item, $cart_item_key ){
if( isset($cart_item['pricing']['active']) && $cart_item['quantity'] > 1 ) {
$product_price = wc_price( wc_get_price_to_display( $cart_item['data'], array( 'price' => $cart_item['pricing']['active'] ) ) );
}
return $product_price;
}
// Display the product name with the a custom "discount" label
add_filter( 'woocommerce_cart_item_name', 'append_custom_label_to_item_name', 20, 3 );
function append_custom_label_to_item_name( $product_name, $cart_item, $cart_item_key ){
if( isset($cart_item['pricing']['discounted']) && $cart_item['data']->get_price() != $cart_item['pricing']['discounted'] ) {
$discounted_price = (float) $cart_item['pricing']['discounted'];
$default_price = (float) $cart_item['pricing']['active'];
$quantity = (int) $cart_item['quantity'];
// Calculate new product price
$new_price = ($default_price + ($discounted_price * ($quantity - 1))) / $quantity;
// Get the discount percentage (if needed)
$percent = 100 - ($new_price / $default_price * 100);
$product_name .= ' <em>(' . __('quantity discounted', 'woocommerce') . ')</em>';
}
return $product_name;
}
// Set the new discounted price
add_action( 'woocommerce_before_calculate_totals', 'set_custom_discount_cart_item_price', 25, 1 );
function set_custom_discount_cart_item_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
foreach( $cart->get_cart() as $cart_item ){
// For items non on sale set a discount based on quantity
if( isset($cart_item['pricing']['discounted']) && $cart_item['quantity'] > 1 ) {
$discounted_price = (float) $cart_item['pricing']['discounted'];
$default_price = (float) $cart_item['pricing']['active'];
$quantity = (int) $cart_item['quantity'];
// Calculate new product price
$new_price = ($default_price + ($discounted_price * ($quantity - 1))) / $quantity;
// Set cart item calculated price
$cart_item['data']->set_price($new_price);
}
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
I would like to alter a specific product in Woocommerce, adding programmatically to its original an amount of $10, EXCEPT in those cases:
On specific product pages that are bookable products for hire (Woocommerce Bookings) that belongs to a certain Category "C".
If any cart item belongs to that category "C".
I was using this answer code to one of my questions until now. But I should need to display this specific product altered price everywhere except on that product pages that are bookable products, in front end.
I have also this code that displays the Force Sells price beside the titles. This should still show the specific product original price on that product pages that are bookable products in the Force Sells section:
function wc_forcesells_product_price( $name, $product ) {
// Only in single product pages
if( ! is_product() ) return $name;
// The product name + the product formatted price
return $name . ' (' . wc_price( wc_get_price_to_display( $product ) ) . ')';
}
add_filter( 'woocommerce_product_title', 'wc_forcesells_product_price', 20, 2 );
Reference for above: Add price beside Woocommerce Force Sells.
Updated to handle multiple product Ids if necessary
Try the following that will display for a specific product ID a custom price everywhere except:
On booking products to hire pages
When a product category is in cart
The code will also change this custom product price in cart items except when a specific product category is in cart items.
You will have to set in those functions:
This specific product ID
The booking products IDs to hire
The Additional price amount
The product category (Id slug or name)
The code:
// Change product ID 87 price everywhere on front end EXCEPT:
// - On booking products to hire pages
// - When a product category is in cart
add_filter( 'woocommerce_get_price_html', 'product_id_87_displayed_price', 10, 2 );
function product_id_87_displayed_price( $price_html, $product ) {
// Only for product ID 87
if( in_array( $product->get_id(), array( 87, 2799 ) ) ){
return $price_html; // Exit
// HERE set booking products IDs to hire in the array
$product_ids_to_hire = array( 53, 738 );
// HERE set your product category term ID, slug or name
$product_category = 'hoodies';
// HERE set the price additional amount
$addp = 10;
// EXCEPT on booking products to hire pages
if( is_single($product_ids_to_hire) ) return $price_html; // Exit
// Checking for the product category in cart items loop
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( has_term( $product_category, 'product_cat', $cart_item['product_id'] ) )
return $price_html; // Product category found ==> Exit
}
if ( '' !== $product->get_price() && ! $product->is_on_sale() ) {
$price_html = wc_price( wc_get_price_to_display( $product ) + $addp ) . $product->get_price_suffix();
}
return $price_html;
}
// Add custom calculated price to cart item data for product ID 87
add_filter( 'woocommerce_add_cart_item_data', 'add_cart_simple_product_custom_price', 20, 2 );
function add_cart_simple_product_custom_price( $cart_item_data, $product_id ){
// Only for product ID 87
if( ! in_array( $product->get_id(), array( 87 ) ) )
return $cart_item_data; // Exit
// HERE set the price additional amount
$addp = 10;
$product = wc_get_product($product_id); // The WC_Product Object
$price = (float) $product->get_price(); // The product price
// Set the custom amount in cart object
$cart_item_data['new_price'] = $price + $addp;
return $cart_item_data;
}
// Set custom calculated price to cart for product ID 87
add_action( 'woocommerce_before_calculate_totals', 'set_cart_simple_product_custom_price', 20, 1 );
function set_cart_simple_product_custom_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// HERE set your product category term ID, slug or name
$product_category = 'hoodies';
// 1st cart items Loop: checking for the product category
foreach ( $cart->get_cart() as $cart_item ) {
if ( has_term( $product_category, 'product_cat', $cart_item['product_id'] ) )
return; // Product category found ==> We EXIT from this function
}
// 2nd Loop: Changing cart item prices (Product category not found)
foreach ( $cart->get_cart() as $cart_item ) {
if( isset($cart_item['new_price']))
$cart_item['data']->set_price( $cart_item['new_price'] );
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
It should also work with your wc_forcesells_product_price() function.
In my WooCommerce website I have a few products with the same price of 80$.
I want to add a Discount by the products quantity.
The logic is like that:
if (Products Quantity is 2){
// the original product price change from 80$ to 75$ each.
}
if(Products Quantity is 3 or more){
//the original product price change from 80$ to 70$ each.
}
for example,
if a customer pick 2 products, the original price will be (80$ x 2) => 160$.
But after the discount, it will be: (75$ x 2) => 150$.
And…
if visitor pick 3 products, the original price will be (80$ x 3) => 240$.
But after the fee, it will be: (70$ x 3) => 210$.
Any help, please?
Thanks
This custom hooked function should do what you expect. You can set in it your progressive discount limit based on individual item quantity.
Here is the code
## Tested and works on WooCommerce 2.6.x and 3.0+
add_action( 'woocommerce_cart_calculate_fees', 'progressive_discount_by_item_quantity', 10, 1 );
function progressive_discount_by_item_quantity( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
# Progressive quantity until quantity 3 is reached (here)
# After this quantity limit, the discount by item is fixed
# No discount is applied when item quantity is equal to 1
// Set HERE the progressive limit quantity discount
$progressive_limit_qty = 3; // <== <== <== <== <== <== <== <== <== <== <==
$discount = 0;
foreach( $cart->get_cart() as $cart_item_key => $cart_item ){
$qty = $cart_item['quantity'];
if( $qty <= $progressive_limit_qty )
$param = $qty; // Progressive
else
$param = $progressive_limit_qty; // Fixed
## Calculation ##
$discount -= 5 * $qty * ($param - 1);
}
if( $discount < 0 )
$cart->add_fee( __( 'Quantity discount' ), $discount); // Discount
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works on WooCommerce 2.6.x and 3.0+