Conditionally alter specific product price in Woocommerce - php

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.

Related

Apply/determine discount based on a particular product category only when a specific product is in WooCommerce cart

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 );

Append text to product title on multiple pages in WooCommerce

I'm trying to append text to WooCommerce product title in the order meta - if products has a specific tag. I'm working from
"Append text to product title if product has product-tag on cart in WooCommerce"
"Display custom payment field in Woocommerce Admin, Orders and emails"
This is what I have so fare:
add_filter( 'woocommerce_get_order_item_totals', 'add_udstilling_below_cart_item_name', 10, 3 );
function add_udstilling_below_cart_item_name( $total_rows, $order, $tax_display ) {;
$new_total_rows = [];
foreach($total_rows as $key => $total ){
$new_total_rows[$key] = $total;
}
}
return $new_total_rows;
}
Based on your previous question and this new question, I assume that you would like to see the product title adjusted 'everywhere'.
IMPORTANT!! You should definitely read the following post to
understand that this is a general adjustment, so that you ultimately
no longer need the code from your previous post / question
Changing WooCommerce cart item names
In other words, you can start using the code below to see the adjustment in the following places
Order-receive (Thank you) page,
email notifications
My Account Orders> Single order details
Cart & Checkout and Backend Order edit pages.
Now you have change the names everywhere except on Shop archives and product pages…
function add_udstilling_order_item_name( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get an instance of the WC_Product object
$product = $cart_item['data'];
// Get product id
$product_id = $cart_item['product_id'];
if( method_exists( $product, 'set_name' ) && has_term( 'udstillingsmodel', 'product_tag', $product_id ) ) {
$product->set_name( $product->get_name() . '(test)' );
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'add_udstilling_order_item_name', 10, 1 );

Remove conditionally Woocommerce cart items based on a specific product

A specific WooCommerce product can only be by itself in the cart.
So how do I clear the cart while adding this specific product to the cart? and how can I remove this specific product from the cart when adding any other product?
I've figured out how to empty the cart when adding a specific product but I don't know how to remove this specific product from the cart when adding any other product.
The following will remove conditionally cart items based on a specific product:
When the specific product is added to cart, all other items are removed.
When any other product is added to cart, it removes the specific product (if it's in cart)
Here is the code:
// Remove conditionally cart items based on a specific product (item)
add_action( 'woocommerce_before_calculate_totals', 'remove_cart_items_conditionally', 10, 1 );
function remove_cart_items_conditionally( $cart ) {
// HERE define your specific product ID
$specific_product_id = 37;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$cart_items = $cart->get_cart(); // Cart items array
$items_count = count($cart_items); // Different cart items count
// Continue if cart has at least 2 different cart items
if ( $items_count < 2 )
return;
$last_item = end($cart_items); // Last cart item data array
$is_last_item = false; // Initializing
// Check if the specific product is the last added item
if ( in_array($specific_product_id, array( $last_item['product_id'], $last_item['variation_id'] ) ) ) {
$is_last_item = true;
}
// Loop through cart items
foreach ( $cart_items as $cart_item_key => $cart_item ) {
// Remove all others cart items when specific product ID is the last added to cart
if ( ! in_array($specific_product_id, array( $cart_item['product_id'], $cart_item['variation_id'] ) ) && $is_last_item ) {
$cart->remove_cart_item( $cart_item_key );
}
// Remove the specific item when its is not the last added to cart
elseif ( in_array($specific_product_id, array( $cart_item['product_id'], $cart_item['variation_id'] ) ) && ! $is_last_item ) {
$cart->remove_cart_item( $cart_item_key );
}
}
}
Code goes on function.php file of your active child theme (or active theme). Tested and works.
The above works perfectly! You can also add a notice to the cart once items have been removed to help with the user experience. Add this to the // Loop through cart items section in the first if statement:
wc_add_notice( __( 'Product XYZ has been removed from your cart because...', 'theme_domain' ), 'notice' );

Cart item discount based on quantity in Woocommerce 3

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

Auto add a coupon discount only when cart items are from 3 different product categories

IN WooCommerce I would like to add 10% of discount with WooCommerce Coupon feature, only when customer purchases products from 3 different product categories (like Category1, Category2, Category3).
How this can be done with WooCommerce Coupon feature?
Any help on this will be appreciated.
Update note: I only 3 parent product categories with no sub categories. Each product is assigned to one category. Some products are variable and some others are simple.
Here's a solution that is not using coupon codes that I recycled from this previous question.
add_action( 'woocommerce_cart_calculate_fees' , 'add_multiple_category_discount' );
function add_multiple_category_discount( $cart ){
if( $cart->cart_contents_count < 3 ){
return;
}
$product_cats = array();
foreach( $cart->get_cart() as $item ) {
$product = wc_get_product( $item['product_id'] );
foreach( $product->get_category_ids() as $key => $cat_id ) {
if( ! in_array( $cat_id, $product_cats ) )
$product_cats[] = $cat_id;
}
}
// If we have 3 distinct categories then apply a discount
if( count( $product_cats ) >= 3 ) {
// Add a 10% discount
$discount = $cart->subtotal * 0.1;
$cart->add_fee( 'You have 3 different product categories in your cart, a 10% discount has been added.', -$discount );
}
}
To handle this functionality with a coupon you will need to have one product category by product or one parent category by product, because a product can have many categories and subcategories set for it.
This custom function will add a coupon discount when cart items are from 3 different product categories. If cart items are removed from cart and there is not anymore 3 different product categories, the coupon code will be auto removed.
Also you will need to set in the function the coupon code name and an array of all your matching product categories IDs.
Here is the code:
add_action( 'woocommerce_before_calculate_totals', 'add_discount_for_3_diff_cats', 10, 1 );
function add_discount_for_3_diff_cats( $wc_cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// HERE set your coupon code and your parent product categories in the array
$coupon_code_to_apply = 'summer';
// HERE define your product categories IDs in the array
$your_categories = array( 11, 13, 14 ); // IDs
// If coupon is already set
if( $wc_cart->has_discount( $coupon_code_to_apply ) )
$has_coupon = true;
foreach( $wc_cart->get_cart() as $cart_item ) {
$product_id = $cart_item['product_id'];
$product = wc_get_product($product_id);
foreach( $product->get_category_ids() as $category_id ) {
if( has_term( $your_categories, 'product_cat', $product_id ) && in_array( $category_id, $your_categories ) ){
// Set the categories in an array (avoiding duplicates)
$categories[$category_id] = $category_id;
}
}
}
$count_cats = count($categories);
$has_discount = $wc_cart->has_discount( $coupon_code_to_apply );
if ( 3 <= $count_cats && ! $has_discount ) {
$wc_cart->add_discount($coupon_code_to_apply);
} elseif ( 3 > $count_cats && $has_discount ) {
$wc_cart->remove_coupon($coupon_code_to_apply);
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works with simple and variable products…

Categories