WooCommerce change price to specific attribute taxonomy in variation - php

Hello everyone,
i need to make a function, that will increase price of a product based on value from attribute that user select. For example (not real product) - We have a product with T-shirt. Customer can choose from two attributes - Color and Size. Let say, that it look something like this:
Color: Red / Blue / Green / Yellow / Black
Size: Small / Large
So when customer pick his choice, the price will look like this:
Any Color + Small = 10$;
Any Color + Large = 20$;
Now i need to make a list with 'Premium' colors. Let's assume it's yellow and i want that to increase the price by 20%. So now it should look like this:
Any Color (without yellow) + Small = 10$;
Yellow + Small = 12$;
Any Color (without yellow) + Large = 20$;
Yellow + Large = 24$;
I can't make it from default product variations in Woo, because of a large amount of them.
So i make a textarea with ACF, where i can put simplified name of attribute taxonomy.
I wrote a function, that check available variations for product and get ID's
Here's my code
function increase_price() {
global $product;
$regularPrice = $product->get_price();
if($product->get_type() === 'variable') {
$variations = $product->get_children();
foreach($variations as $variation) {
$vproduct = wc_get_product($variation);
$premiumList = get_field( "color_list", 3096 ); // From ACF - field with 'premium colors'
$premiumSep = explode(",", $premiumList);
$vNames = $vproduct->attributes{"pa_color"};
if (in_array($vNames, $premiumSep)){
$markupPrice = $vproduct->get_price();
$selfVarID = $vproduct->get_id();
$VarPrice = $markupPrice * 1.2;
$VarPrice = ceil($VarPrice);
// update_post_meta( $selfVarID, '_regular_price', $VarPrice );
// update_post_meta( $selfVarID, '_price', $VarPrice );
// ^ it change the price in backend
} else {
}
}
}
}
So it works with 'update_post_meta' but if someone change the price via Backend (Product Edit), it won't increase the price. My question is, how i can change the price permanently only for taxonomies on list?
Thanks and have a great day :)

If someone saves the product in wp-admin, you can trigger your function on save_post_product hook
For example, simplified version of your code
function increase_variation_prices_on_save($post_id) {
$product = wc_get_product($post_id);
if($product->get_type() === 'variable') {
$variations = $product->get_children();
foreach($variations as $variation_id) {
$vproduct = wc_get_product($variation_id);
$markupPrice = $vproduct->get_price();
$VarPrice = $markupPrice * 1.2;
$VarPrice = ceil($VarPrice);
update_post_meta( $variation_id, '_regular_price', $VarPrice );
update_post_meta( $variation_id, '_price', $VarPrice );
}
}
}
add_action('save_post_product', 'increase_variation_prices_on_save', 10, 1);
but, there is one problem , this will increase the price every time you save your parent product!
It happens because your base price is the variation price so every time you save, the last increased price becomes the new base price.
Instead, you should pull the base price, or markup price from the parent product, before the loop, like this.
function increase_variation_prices_on_save($post_id) {
$product = wc_get_product($post_id);
$markupPrice = $product->get_price();
if($product->get_type() === 'variable') {
$variations = $product->get_children();
foreach($variations as $variation_id) {
$vproduct = wc_get_product($variation_id);
$VarPrice = $markupPrice * 1.2;
$VarPrice = ceil($VarPrice);
update_post_meta( $variation_id, '_regular_price', $VarPrice );
update_post_meta( $variation_id, '_price', $VarPrice );
}
}
}
add_action('save_post_product', 'increase_variation_prices_on_save', 10, 1);
But what is the price of the parent product if you can't configure it in wp-admin? It's the price you add when you create variations. WooCommerce will ask you to set a price for all variations that don't have price. It's then stored in _price metadata under the parent product id.
And finally, your function which I wasn't able to test, it would take me too much time to create a setup like yours but it should work.
function increase_price() {
global $product;
$basePrice = $product->get_price();
if($product->get_type() === 'variable') {
$variations = $product->get_children();
foreach($variations as $variation) {
$vproduct = wc_get_product($variation);
$premiumList = get_field( "color_list", 3096 ); // From ACF - field with 'premium colors'
$premiumSep = explode(",", $premiumList);
$vNames = $vproduct->attributes["pa_color"];
if (in_array($vNames, $premiumSep)){
$selfVarID = $vproduct->get_id();
$VarPrice = $basePrice * 1.2;
$VarPrice = ceil($VarPrice);
update_post_meta( $selfVarID, '_regular_price', $VarPrice );
update_post_meta( $selfVarID, '_price', $VarPrice );
}
}
}
}
Have a great day too :)

Related

NEW and BACK IN STORE badge display - WooCommerce product

Based on that question Display custom product badge when a product is back in stock WooCommerce I created a snipped to display NEW or BACK IN STORE badge based on conditions. We want, if the product is published the first time to display the NEW badge for 15 days. IF a product is out of stock in the future and comes available again, then we want to display BACK IN STOCK badge. By default when we only use the modified date, then it will always display the NEW badge.
That's why we created this code below but it does not fully work :(
The NEW badge is displayed right for the given time. We have problems to display the BACK IN STORE badge.
Is there a logical error in my code or what i'm doing wrong?
// Check if product was out of stock
add_action( 'woocommerce_updated_product_stock', 'woo_updated_product_stock', 10, 3);
add_action( 'woocommerce_update_product', 'woo_updated_product_stock',10, 3 );
add_action('save_post_product', 'woo_updated_product_stock', 10, 3);
function woo_updated_product_stock( $product_id ) {
$product = wc_get_product( $product_id );
$stock_qty = $product->get_stock_quantity();
if ($stock_qty >=1) {
update_post_meta( $product_id, '_earlier_update', true);
}else{
update_post_meta( $product_id, '_earlier_update', false);
}
}
add_action('woocommerce_checkout_order_processed', 'stocktest');
function stocktest($order_id){
$order = wc_get_order( $order_id );
$order_item = $order->get_items();
foreach( $order_item as $product ) {
$productID = $product['product_id'];
//for the topic I programmed the IDs hardcoded
if($productID){
$quantity = $product['quantity'];
global $product;
$connected_product = wc_get_product($productID);
$connected_qty = $connected_product->get_stock_quantity();
if(isset($connected_qty)){
$qty = $connected_qty - $quantity;
if ($qty < 1) {
update_post_meta( $productID, '_outofstockproduct', true);
}
}
}
}
}
// Set "NEW" badge for new products (first time published)
function action_woocommerce_before_shop_loop_item_title() {
global $product;
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// 15 days in seconds
$days_count = 15 * 24 * 60 *60; //15 * 24 * 60 *60
// Get now datetime (from Woocommerce datetime object) + Get now timestamp
$datetime_now = new WC_DateTime();
$timestamp_now = $datetime_now->getTimestamp();
// Get product created datetime + product created timestamp
$datetime_created = $product->get_date_created();
$timestamp_created = $datetime_created->getTimestamp();
// print_r($datetime_created);
// exit();
// Difference in seconds between now and date created
$time_delta_created = $timestamp_now - $timestamp_created;
// If the difference is less than 10, apply "New" label
if ( $time_delta_created < $days_count && $product->is_in_stock() ) {
echo '<div class="badge_loop_wrapper"><img src="/wp-content/uploads/2021/01/new_badge.png"/></div>';
// echo '<span>' . __( 'New Label', 'woocommerce' ) . '</span>';
}
// Set "BACK IN STOCK" badge for products which are not published the first time and was out of stock
else {
global $product;
$newness_days = 15;
$product_id = $product->get_id();
$date_modified = $product->get_date_modified()->date('Y-m-d');
// Add 15 day on product modify date becase fresh back in stock will show 10 days from current modify dates
$back_in_stock = strtotime($date_modified. " + $newness_days day");
$today = strtotime(date('Y-m-d'));
$earlier_update = get_post_meta( $product_id, '_earlier_update', true );
$outofstockproduct = get_post_meta( $product_id, '_outofstockproduct', true );
if (($outofstockproduct && $earlier_update && $today < $back_in_stock) && !$product->is_on_sale() && $product->is_in_stock() && get_post_meta( $product->get_id(), 'custom_badge', true) !== 'yes' ) {
//echo '<div class="badge_loop_wrapper">'.__('Back in stock').'</div>';
echo '<div class="badge_loop_wrapper"><img src="/wp-content/uploads/2021/09/back_in_stock_badge.png"/></div>';
}
}
}
}
add_action( 'woocommerce_before_shop_loop_item_title', 'action_woocommerce_before_shop_loop_item_title', 10 );
You should add/update product meta data when update product:
Add/update custom product meta:
add_action( 'woocommerce_updated_product_stock', 'back_product_stock', 10, 3);
add_action( 'woocommerce_update_product', 'back_product_stock',10, 3 );
add_action('save_post_product', 'back_product_stock', 10, 3);
function back_product_stock( $product_id ) {
$product = wc_get_product( $product_id );
$stock_qty = $product->get_stock_quantity();
if ($stock_qty >=1) {
update_post_meta( $product_id, '_earlier_update', true);
}
else{
update_post_meta( $product_id, '_earlier_update', false);
}
}
Display custom product badge when a product is back in stock WooCommerce
add_action( 'woocommerce_before_shop_loop_item_title', function() {
global $product;
$newness_days = 10;
$product_id = $product->get_id();
$date_modified = $product->get_date_modified()->date('Y-m-d');
// Add 10 day on product modify date becase fresh back in stock will show 10 days from current modify dates
$back_in_stock = strtotime($date_modified. " + $newness_days day");
$today = strtotime(date('Y-m-d'));
$earlier_update = get_post_meta( $product_id, '_earlier_update', true );
if (($earlier_update && $today < $back_in_stock) && !$product->is_on_sale() && $product->is_in_stock() && get_post_meta( $product->get_id(), 'custom_badge', true) !== 'yes' ) {
echo '<div class="badge_loop_wrapper">'.__('Back in stock').'</div>';
}
});
You can change the action and condition accordingly.
Let me know if any other question.
Thanks!

WooCommerce: Get price of chosen product variation

I am making a custom add-on for my products on my WooCommerce webshop. Everything works as it should, but I only need one thing. When customers check the checkbox on the product page, $30 must be added to the original price of the selected variation.
add_filter( 'woocommerce_add_cart_item_data', 'add_cart_item_data', 10, 3 );
function add_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
$product = wc_get_product($product_id);
$price = $product->get_price();
if ($product->is_type( 'variable' )) {
$var_price = $product->get_price_html();
// extra pack checkbox
if( ! empty( $_POST['addon-card'] ) ) {
$cart_item_data['new_price'] = $var_price + 30;
}
} else {
// extra pack checkbox
if( ! empty( $_POST['addon-card'] ) ) {
$cart_item_data['new_price'] = $price + 30;
}
}
return $cart_item_data;
}
This part: if( ! empty( $_POST['addon-card'] ) ) check if the checkbox is checked.
My problem is here:
$var_price = $product->get_price_html();
// extra pack checkbox
if( ! empty( $_POST['addon-card'] ) ) {
$cart_item_data['new_price'] = $var_price + 30;
}
The value of $var_price is just 0.
So I try to figure out how I can get the price of the chosen variation.
I have tried with get_variation_prices() and get_variation_price() but without any luck...
UPDATE
I have tried to implement the code from this thread. With that code I can get the price of the chosen variation, but I can no longer add the $30.
Can you please try below WooCommerce hook to change price dynamically?
add_filter('woocommerce_variation_prices_price', 'custom_variation_price_change', 10, 3 );
add_filter('woocommerce_variation_prices_regular_price', 'custom_variation_price_change', 10, 3 );
function custom_variation_price_change( $price, $variation, $product ) {
// add some conditional code as per your requirement
$price = $price+30;
}

Woocommerce single variation price displaying not as intended

On our woocommerce site we have a price range that is from the lowest price to the highest price.$2 - $600 for example. Then we have a 10% discount on the whole range so it will then display as strikethrough the whole range $2 - $600 and display $1.80 - $540 for example.
When I now select a single variation it displays $540 - $0 for example. But I only want the $540 to display and the - $0 must be removed. I will show a screenshot example.
I have tried various filters but the actual output of a single variation price have not changed.
add_filter( 'woocommerce_get_price_html', 'custom_price_format', 10, 2 );
add_filter( 'woocommerce_variable_price_html', 'custom_price_format', 10, 2 );
function custom_price_format( $price, $product ) {
// 1. Variable products
if( $product->is_type('variable') ){
// Searching for the default variation
$default_attributes = $product->get_default_attributes();
// Loop through available variations
foreach($product->get_available_variations() as $variation){
$found = true; // Initializing
// Loop through variation attributes
foreach( $variation['attributes'] as $key => $value ){
$taxonomy = str_replace( 'attribute_', '', $key );
// Searching for a matching variation as default
if( isset($default_attributes[$taxonomy]) && $default_attributes[$taxonomy] != $value ){
$found = false;
break;
}
}
// When it's found we set it and we stop the main loop
if( $found ) {
$default_variaton = $variation;
break;
} // If not we continue
else {
continue;
}
}
// Get the default variation prices or if not set the variable product min prices
$regular_price = $product->get_variation_regular_price( 'min', true );
$sale_price = $product->get_variation_sale_price( 'min', true );
$regular_price_max = $product->get_variation_regular_price('max', true);
$sale_price_max = $product->get_variation_sale_price( 'max', true );
}
// 2. Other products types
else {
$regular_price = $product->get_regular_price();
$sale_price = $product->get_sale_price();
}
// Formatting the price
if ( $regular_price !== $sale_price && $product->is_on_sale()) {
// Percentage calculation and text
$percentage = round( ( $regular_price - $sale_price ) / $regular_price * 100 ).'%';
$txt = " - ";
$price = '<del>'.wc_price($regular_price).'</del><ins>'.$txt.'</ins><del>'.wc_price($regular_price_max).'</del><br><ins>'.wc_price($sale_price).$txt.wc_price($sale_price_max).'</ins>';
}
return $price;
}
add_filter( 'woocommerce_show_variation_price', 'filter_show_variation_price', 10, 3 );
function filter_show_variation_price( $condition, $product, $variation ){
if( $variation->get_price() === "" ) return false;
else return true;
}
That is my filters I currently have on my functions.php file.
Here is a screenshot of my problem:
I want the range variation price to show with the sale price and regular price with a strikethrough but only a single price to show as soon as you select a variation.
add_filter( 'woocommerce_get_price_html', 'custom_price_format', 10, 2 );
add_filter( 'woocommerce_variable_price_html', 'custom_price_format', 10, 2 );
function custom_price_format( $price, $product ) {
// 1. Variable products
if( $product->is_type('variable') ){
// Searching for the default variation
$default_attributes = $product->get_default_attributes();
// Loop through available variations
foreach($product->get_available_variations() as $variation){
$found = true; // Initializing
// Loop through variation attributes
foreach( $variation['attributes'] as $key => $value ){
$taxonomy = str_replace( 'attribute_', '', $key );
// Searching for a matching variation as default
if( isset($default_attributes[$taxonomy]) && $default_attributes[$taxonomy] != $value ){
$found = false;
break;
}
}
// When it's found we set it and we stop the main loop
if( $found ) {
$default_variaton = $variation;
break;
} // If not we continue
else {
continue;
}
}
// Get the default variation prices or if not set the variable product min prices
$regular_price = $product->get_variation_regular_price( 'min', true );
$sale_price = $product->get_variation_sale_price( 'min', true );
$regular_price_max = $product->get_variation_regular_price('max', true);
$sale_price_max = $product->get_variation_sale_price( 'max', true );
}
// 2. Other products types
else {
$regular_price = $product->get_regular_price();
$sale_price = $product->get_sale_price();
}
// Formatting the price
if ( $regular_price !== $sale_price && $product->is_on_sale()) {
// Percentage calculation and text
$percentage = round( ( $regular_price - $sale_price ) / $regular_price * 100 ).'%';
$txt = " - ";
//Check if Sale Price Exists
if(wc_price($sale_price_max) !== 0.00){
$price = '<del>'.wc_price($regular_price).'</del><ins>'.$txt.'</ins><del>'.wc_price($regular_price_max).'</del><br><ins>'.wc_price($sale_price).$txt.wc_price($sale_price_max).'</ins>';
} else {
//else return price without second sale price
$price = '<del>'.wc_price($regular_price).'</del><ins>'.$txt.'</ins><del>'.wc_price($regular_price_max).'</del><br><ins>'.wc_price($sale_price).'</ins>';
}
}
return $price;
}
Please try the above code and let me know.

Display on sale variation saving amount for WooCommerce variable products

I am having a custom plugin which is used to show accessories. I want to display total savings of main product and accessories combined. my saving works if the main product is simple if the main product is variable the savings shows null. can someone update my code, please
I tried this code to show saving but it is just working for simple products
function you_save_echo_product() {
global $product;
// works for Simple and Variable type
$regular_price = get_post_meta( $product->get_id(), '_regular_price', true ); // 36.32
$sale_price = get_post_meta( $product->get_id(), '_sale_price', true ); // 24.99
if( !empty($sale_price) ) {
$saved_amount = $regular_price - $sale_price;
$currency_symbol = get_woocommerce_currency_symbol();
$percentage = round( ( ( $regular_price - $sale_price ) / $regular_price ) * 100 );
?>
<p id="saving_total_price">You Save: <span class="symbol"><?php echo $currency_symbol; ?></span> <span class="amount"><?php echo $saved_amount; ?></span>.00</p>
<?php
}
}
add_action( 'woocommerce_single_product_summary', 'you_save_echo_product', 11 );
I expect to show total savings for my accessories with the main product as a variable
I have revisited your code as it's is a bit outdated and old… On variable products there is 2 prices, a price range and the selected variation price, so you need something completely different to display the saving amount of the selected variation price.
I have added also the saving percentage (that you can remove if you don't need it).
// For simple products
add_action( 'woocommerce_single_product_summary', 'simple_product_saving_amount', 11 );
function simple_product_saving_amount() {
global $product;
if( $product->is_type('simple') && $product->is_on_sale() ) {
$regular_price = (float) wc_get_price_to_display( $product, array('price' => $product->get_regular_price() ) );
$active_price = (float) wc_get_price_to_display( $product, array('price' => $product->get_sale_price() ) );
$saved_amount = $regular_price - $active_price;
$percentage = round( $saved_amount / $regular_price * 100 );
echo '<p id="saving_total_price">'. __("You Save") .': ' . wc_price($saved_amount) . ' ('.$percentage.'%)</p>';
}
}
// For product variations (on variable products)
add_filter( 'woocommerce_available_variation', 'variable_product_saving_amount', 10, 3 );
function variable_product_saving_amount( $data, $product, $variation ) {
if( $variation->is_on_sale() ) {
$saved_amount = $data['display_regular_price'] - $data['display_price'];
$percentage = round( $saved_amount / $data['display_regular_price'] * 100 );
$data['price_html'] .= '<p id="saving_total_price">'. __("You Save") .': ' . wc_price($saved_amount) . ' ('.$percentage.'%)</p>';
}
return $data;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Error when adding product with custom pricing to cart - WooCommerce

I have set up a custom user role with a slug of performance_customer. I am checking to see if the current user is a "performance customer" and apply certain price discounts to products in specific categories.
Here is my code:
function return_custom_performance_dealer_price($price, $product) {
global $woocommerce;
global $post;
$terms = wp_get_post_terms( $post->ID, 'product_cat' );
foreach ( $terms as $term ) $categories[] = $term->slug;
$origPrice = get_post_meta( get_the_ID(), '_regular_price', true);
$price = $origPrice;
//check if user role is performance dealer
$current_user = wp_get_current_user();
if( in_array('performance_customer', $current_user->roles)){
//if is category performance hard parts
if(in_array( 'new-hard-parts-150', $categories )){
$price = $origPrice * .85;
}
//if is category performance clutches
elseif(in_array( 'performance-clutches-and-clutch-packs-150', $categories )){
$price = $origPrice * .75;
}
//if is any other category
else{
$price = $origPrice * .9;
}
}
return $price;
}
add_filter('woocommerce_get_price', 'return_custom_performance_dealer_price', 10, 2);
The function works perfectly in the product loop, but when I added a product to the cart it blew up and gave me this error for each line containing if(in_array( 'CATEGORY_NAME_HERE', $categories )){.
Error: Warning: in_array() expects parameter 2 to be array, null given in…
I'm guessing this has to do with the 5th line of the code above where I use wp_get_post_terms() to form an array of the categories that each product belongs to. I'm not sure how to make this work.
First, the filter hook woocommerce_product_get_price is now replacing deprecated hook woocommerce_get_price…
To avoid the error you got you should use Wordpress conditional dedicated function has_term()
I have revisited your code a bit, so please try this instead:
add_filter('woocommerce_product_get_price', 'return_custom_performance_dealer_price', 10, 2);
function return_custom_performance_dealer_price( $price, $product ) {
$price = $product->get_regular_price();
//check if user role is performance dealer
$current_user = wp_get_current_user();
if( in_array('performance_customer', $current_user->roles) ){
//if is category performance hard parts
if( has_term( 'new-hard-parts-150', 'product_cat', $product->get_id() ) ){
$price *= .85;
}
//if is category performance clutches
elseif( has_term( 'performance-clutches-and-clutch-packs-150', 'product_cat', $product->get_id() ) ){
$price *= .75;
}
//if is any other category
else{
$price *= .9;
}
}
return $price;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested for WooCommerce 3+… It should work now…

Categories