Set product sale price programmatically in WooCommerce 3 - php

I have a Woocommerce store set up with various product categories.
I want to apply a 20% discount to all products, which belong to the product category Cuckoo
For now all I'm trying to achieve is set a sale price in my functions.php
It tried as follows:
/*
* For a specific date, 20% off all products with product category as cuckoo clock.
*/
function cuckoo_minus_twenty($sale_price, $product) {
$sale_price = $product->get_price() * 0.8;
return $sale_price;
};
// add the action
add_filter( 'woocommerce_get_sale_price', 'cuckoo_minus_twenty', 10, 2 );
If I var_dump the result of $sale_price after the calculation I get the correct answer, however the price display on the front-end strikes out the regular price and displays the sale price as the regular price.
Is there a hook/filter I can use to achieve this?
I've also tried setting the sale price by doing:
$product->set_sale_price($sale_price);
to no avail.

The hook woocommerce_get_sale_price is deprecated since WooCommerce 3 and replaced by woocommerce_product_get_sale_price.
Also Product displayed prices are cached. When sale price is active, regular price is also active.
Try this instead:
// 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 ) {
$rate = 0.8;
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;
$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;
}
Code goes in function.php file of your active child theme (active theme).
Tested and works on single product, shop, product category and tag archive pages.
The continuation in:
Wrong Woocommerce cart item price after setting programmatically product sale price

I realiced, you more or less need all of the following filters to make the HTML work out of the box.
add_filter( 'woocommerce_product_get_price', 'custom_dynamic_sale_price', 10, 2 );
add_filter( 'woocommerce_product_variation_get_price', 'custom_dynamic_sale_price', 10, 2 );
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 );
add_filter( 'woocommerce_variation_prices_price', 'custom_dynamic_sale_price', 10, 2 );
add_filter( 'woocommerce_variation_prices_sale_price', 'custom_dynamic_sale_price', 10, 2 );
And you need to make sure you've changed the woocommerce_get_variation_prices_hash becasue of the stored transients if you want to display it correctly for variable products.
You may find the gist i've created for a client useful
https://gist.github.com/xandl/743fb6af60827eb95ad42b20b478b020

use woocomerce_get_sale_price filter.
add_filter('woocommerce_get_sale_price', 'my_custom_price', 99, 2);
add_filter('woocommerce_get_price', 'my_custom_price', 99, 2);
function my_custom_price( $price, $product )
{
//your logic for calculating the new price here
$price = $product->get_regular_price() * 0.8;
//Return the new price (this is the price that will be used everywhere in the store)
return $price;
}

Related

WooCommerce cart items price suffix for specific product category

I need to add a suffix text to the price of a woocommerce product from a specific category while on WooCommerce cart.
Here is my code:
add_filter( 'woocommerce_cart_item_price', 'filter_woocommerce_cart_item_price', 10, 3 );
add_filter( 'woocommerce_cart_item_subtotal', 'filter_woocommerce_cart_item_price', 10, 3 );
function filter_woocommerce_cart_item_price( $wc, $cart_item, $cart_item_key ) {
if(!in_array('67',$cart_item['data']->get_category_ids()))
{
return $wc;
}
else{
return $wc . ' Monthly';
}
};
The problem is it only works on simple products. Doesn't seem to affect the prices of variable products (I tested on 3 different sites).
Any idea what I'm missing?
To make it work for product variations items in cart too, use instead the following:
add_filter( 'woocommerce_cart_item_price', 'cart_item_amounts_prefix', 10, 3 );
add_filter( 'woocommerce_cart_item_subtotal', 'cart_item_amounts_prefix', 10, 3 );
function cart_item_amounts_prefix( $amount, $cart_item, $cart_item_key ) {
if( has_term( array(67), 'product_cat', $cart_item['product_id'] ) ){
$amount .= ' ' . __("Monthly", "woocommerce");
}
return $amount;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.

WooCommerce Hide Price for only certain categories [duplicate]

In Woocommerce I am trying to hide the product on the archive page and single product page based on category however the condition does not appear to work and just hide all the price whether I set the category or not
add_filter( 'woocommerce_variable_sale_price_html', 'woocommerce_remove_prices', 10, 2 );
add_filter( 'woocommerce_variable_price_html', 'woocommerce_remove_prices', 10, 2 );
add_filter( 'woocommerce_get_price_html', 'woocommerce_remove_prices', 10, 2 );
function woocommerce_remove_prices( $price, $product ) {
if(is_product_category('sold')){
$price = '';
return $price;
}
}
To make your code working you should need to use has_term() conditional function for single product pages and you will need to always return the price at the end, outside the if statement:
add_filter( 'woocommerce_variable_sale_price_html', 'woocommerce_remove_prices', 10, 2 );
add_filter( 'woocommerce_variable_price_html', 'woocommerce_remove_prices', 10, 2 );
add_filter( 'woocommerce_get_price_html', 'woocommerce_remove_prices', 10, 2 );
function woocommerce_remove_prices( $price, $product ) {
if( is_product_category('sold') || has_term( 'sold', 'product_cat', $product->get_id() ) )
$price = '';
return $price;
}
It works! But this will not remove the selected product variation price and everywhere you still have the add to cart buttons.
Code goes in function.php file of your active child theme (or active theme).
Instead you could use the following that will remove all prices, quantity buttons and add-to-cart buttons on that specific product category:
// Specific product category archive pages
add_action( 'woocommerce_after_shop_loop_item_title', 'hide_loop_product_prices', 1 );
function hide_loop_product_prices(){
global $product;
if( is_product_category('sold') ):
// Hide prices
remove_action('woocommerce_after_shop_loop_item_title', 'woocommerce_template_loop_price', 10 );
// Hide add-to-cart button
remove_action('woocommerce_after_shop_loop_item','woocommerce_template_loop_add_to_cart', 30 );
endif;
}
// Single product pages
add_action( 'woocommerce_single_product_summary', 'hide_single_product_prices', 1 );
function hide_single_product_prices(){
global $product;
if( has_term( 'sold', 'product_cat', $product->get_id() ) ):
// Hide prices
remove_action('woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
// Hide add-to-cart button, quantity buttons (and attributes dorpdowns for variable products)
if( ! $product->is_type('variable') ){
remove_action('woocommerce_single_product_summary','woocommerce_template_single_add_to_cart', 30 );
} else {
remove_action( 'woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', 20 );
}
endif;
}
Code goes in function.php file of your active child theme (or active theme).
Tested and works.

Hide Price based on product category in Woocommerce

In Woocommerce I am trying to hide the product on the archive page and single product page based on category however the condition does not appear to work and just hide all the price whether I set the category or not
add_filter( 'woocommerce_variable_sale_price_html', 'woocommerce_remove_prices', 10, 2 );
add_filter( 'woocommerce_variable_price_html', 'woocommerce_remove_prices', 10, 2 );
add_filter( 'woocommerce_get_price_html', 'woocommerce_remove_prices', 10, 2 );
function woocommerce_remove_prices( $price, $product ) {
if(is_product_category('sold')){
$price = '';
return $price;
}
}
To make your code working you should need to use has_term() conditional function for single product pages and you will need to always return the price at the end, outside the if statement:
add_filter( 'woocommerce_variable_sale_price_html', 'woocommerce_remove_prices', 10, 2 );
add_filter( 'woocommerce_variable_price_html', 'woocommerce_remove_prices', 10, 2 );
add_filter( 'woocommerce_get_price_html', 'woocommerce_remove_prices', 10, 2 );
function woocommerce_remove_prices( $price, $product ) {
if( is_product_category('sold') || has_term( 'sold', 'product_cat', $product->get_id() ) )
$price = '';
return $price;
}
It works! But this will not remove the selected product variation price and everywhere you still have the add to cart buttons.
Code goes in function.php file of your active child theme (or active theme).
Instead you could use the following that will remove all prices, quantity buttons and add-to-cart buttons on that specific product category:
// Specific product category archive pages
add_action( 'woocommerce_after_shop_loop_item_title', 'hide_loop_product_prices', 1 );
function hide_loop_product_prices(){
global $product;
if( is_product_category('sold') ):
// Hide prices
remove_action('woocommerce_after_shop_loop_item_title', 'woocommerce_template_loop_price', 10 );
// Hide add-to-cart button
remove_action('woocommerce_after_shop_loop_item','woocommerce_template_loop_add_to_cart', 30 );
endif;
}
// Single product pages
add_action( 'woocommerce_single_product_summary', 'hide_single_product_prices', 1 );
function hide_single_product_prices(){
global $product;
if( has_term( 'sold', 'product_cat', $product->get_id() ) ):
// Hide prices
remove_action('woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
// Hide add-to-cart button, quantity buttons (and attributes dorpdowns for variable products)
if( ! $product->is_type('variable') ){
remove_action('woocommerce_single_product_summary','woocommerce_template_single_add_to_cart', 30 );
} else {
remove_action( 'woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', 20 );
}
endif;
}
Code goes in function.php file of your active child theme (or active theme).
Tested and works.

Checkout price issue using woocommerce_product_get_price hook

I need to double the price for every product in Woocommerce frontend. For this I used the following code:
add_filter( 'woocommerce_product_get_price', 'double_price', 10, 2 );
function double_price( $price, $product ){
return $price*2;
}
But there is an error using this code. checkout page price is not correct.
for example the product orginal price is 10. We double the price by this code . so the product price is 20 now. When i added this product to the cart then cart and checkout page price is 40. That means this multiplication is take place in two times.
Please help to solve this.
Updated To double the price:
1) First you will restrict your code to single product and archives pages only:
add_filter( 'woocommerce_product_get_price', 'double_price', 10, 2 );
function double_price( $price, $product ){
if( is_shop() || is_product_category() || is_product_tag() || is_product() )
return $price*2;
return $price;
}
2) Then for cart and checkout pages, you will change the cart item price this way:
add_filter( 'woocommerce_add_cart_item', 'set_custom_cart_item_prices', 20, 2 );
function set_custom_cart_item_prices( $cart_data, $cart_item_key ) {
// Price calculation
$new_price = $cart_data['data']->get_price() * 2;
// Set and register the new calculated price
$cart_data['data']->set_price( $new_price );
$cart_data['new_price'] = $new_price;
return $cart_data;
}
add_filter( 'woocommerce_get_cart_item_from_session', 'set_custom_cart_item_prices_from_session', 20, 3 );
function set_custom_cart_item_prices_from_session( $session_data, $values, $key ) {
if ( ! isset( $session_data['new_price'] ) || empty ( $session_data['new_price'] ) )
return $session_data;
// Get the new calculated price and update cart session item price
$session_data['data']->set_price( $session_data['new_price'] );
return $session_data;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and working. It will change all prices as you expect in cart, checkout and order pages…

Change product prices via a hook in WooCommerce 3+

IN WooCommerce, I need to multiply all product prices by a number. So I have used the following (via a plugin):
add_filter('woocommerce_get_regular_price', array( $this, 'my_custom_price'), 99);
add_filter('woocommerce_get_price', array( $this, 'my_custom_price'), 99);
function my_custom_price( $original_price ) {
global $post, $woocommerce;
//Logic for calculating the new price here
$new_price = $original_price * 2;
//Return the new price (this is the price that will be used everywhere in the store)
return $new_price;
}
But, that doesn't work for variation products. I have tried the following hooks with no luck:
add_filter('woocommerce_get_variation_regular_price', array( $this, 'my_custom_price'), 99);
add_filter('woocommerce_get_variation_price', array( $this, 'my_custom_price'), 99);
The only one that works half way is this one:
add_filter('woocommerce_variation_prices_price', array( $this, 'my_custom_price'), 99);
But that just changed the overall price, not the selected variation price. See the image below, price is BsF. 200 and the overall price is right, 200 x 2 = 400, but the variation price when selected still shows 200:
Note: I need it to actually change, so display html hooks wont work.
Is there anything I'm missing, or something wrong?
Update (December 2020)
2 code versions for themes and plugins (works in Woocommerce 3.3.x too)
Cached variations prices in Woocommerce 3 (Update and addition): Now using woocommerce_get_variation_prices_hash filter hook much more efficient, instead of wc_delete_product_transients()… See this related thread
Added product price filter widget hooks (see at the end).
1) Plugin version with a constructor function:
The hooks that you are using are deprecated in WooCommerce 3+
To make it work for all products prices, including variations prices, you should use this:
## The following goes inside the constructor ##
// Simple, grouped and external products
add_filter('woocommerce_product_get_price', array( $this, 'custom_price' ), 99, 2 );
add_filter('woocommerce_product_get_regular_price', array( $this, 'custom_price' ), 99, 2 );
// Variations
add_filter('woocommerce_product_variation_get_regular_price', array( $this, 'custom_price' ), 99, 2 );
add_filter('woocommerce_product_variation_get_price', array( $this, 'custom_price' ), 99, 2 );
// Variable (price range)
add_filter('woocommerce_variation_prices_price', array( $this, 'custom_variable_price' ), 99, 3 );
add_filter('woocommerce_variation_prices_regular_price', array( $this, 'custom_variable_price' ), 99, 3 );
// Handling price caching (see explanations at the end)
add_filter( 'woocommerce_get_variation_prices_hash', array( $this, 'add_price_multiplier_to_variation_prices_hash' ), 99, 3 );
## This goes outside the constructor ##
// Utility function to change the prices with a multiplier (number)
public function get_price_multiplier() {
return 2; // x2 for testing
}
public function custom_price( $price, $product ) {
return (float) $price * get_price_multiplier();
}
public function custom_variable_price( $price, $variation, $product ) {
return (float) $price * get_price_multiplier();
}
public function add_price_multiplier_to_variation_prices_hash( $price_hash, $product, $for_display ) {
$price_hash[] = get_price_multiplier();
return $price_hash;
}
The code tested and perfectly works (only) in WooCommerce 3+.
2) For theme version: functions.php file on active child theme (or active theme):
// Utility function to change the prices with a multiplier (number)
function get_price_multiplier() {
return 2; // x2 for testing
}
// Simple, grouped and external products
add_filter('woocommerce_product_get_price', 'custom_price', 99, 2 );
add_filter('woocommerce_product_get_regular_price', 'custom_price', 99, 2 );
// Variations
add_filter('woocommerce_product_variation_get_regular_price', 'custom_price', 99, 2 );
add_filter('woocommerce_product_variation_get_price', 'custom_price', 99, 2 );
function custom_price( $price, $product ) {
return (float) $price * get_price_multiplier();
}
// Variable (price range)
add_filter('woocommerce_variation_prices_price', 'custom_variable_price', 99, 3 );
add_filter('woocommerce_variation_prices_regular_price', 'custom_variable_price', 99, 3 );
function custom_variable_price( $price, $variation, $product ) {
// Delete product cached price (if needed)
// wc_delete_product_transients($variation->get_id());
return (float) $price * get_price_multiplier();
}
// Handling price caching (see explanations at the end)
add_filter( 'woocommerce_get_variation_prices_hash', 'add_price_multiplier_to_variation_prices_hash', 99, 3 );
function add_price_multiplier_to_variation_prices_hash( $price_hash, $product, $for_display ) {
$price_hash[] = get_price_multiplier();
return $price_hash;
}
Tested and works on woocommerce 3+
For products in sale you have those hooks:
woocommerce_product_get_sale_price (Simple, grouped and external products)
woocommerce_variation_prices_sale_price (Variable products (min-max))
woocommerce_product_variation_get_sale_price (Products variations)
Cached prices and woocommerce 3:
The 3 filters hooks involved in variations cached prices are:
woocommerce_variation_prices_price
woocommerce_variation_prices_regular_price
woocommerce_variation_prices_sale_price
Introduced in Woocommerce 3, woocommerce_get_variation_prices_hash filter hook will allow to refresh variations cached prices in a much more efficient way, without deleting related transients anytime that this hooks are executed.
So performances will stay boosted (Thanks to Matthew Clark that pointed this better way)
See: Caching and dynamic pricing – upcoming changes to the get_variation_prices method
For filtering product prices with a widget (min and max price), use the following hooks:
woocommerce_price_filter_widget_min_amount that has one argument $price
woocommerce_price_filter_widget_max_amount that has one argument $price

Categories