WooCommerce - Product variation single price changes after delay - woocommerce

I am currently using a php snippet to adjust the amount of decimals displayed for a specific product category.
function custom_price_decimals( $decimals ) {
if( is_product()) {
global $post;
$terms = wp_get_post_terms( $post->ID, 'product_cat' );
foreach ( $terms as $term ) $categories[] = $term->slug;
if ( in_array( 'standard-eyelets', $categories ) ) {
$decimals = 3;
}
}
return $decimals;
}
add_filter( 'wc_get_price_decimals' , 'custom_price_decimals', 20, 1 );
This works but after a slight delay, for some reason for single variation prices, the 3 decimals changes back to two decimals. I disabled my other code snippets to see if they were causing the issue but they were not. Is there some sort of hook that happens to change the price back to 2 decimals? This does not happen for single or grouped products.
A similar question was asked here but never answered (Woocommerce: 3 decimals in product variation price)
I expected that the single variation price would display 3 decimals and it does. But then after a delay, it changes back to rounding to 2 decimals.

Related

Separate attribute term from variable dropdown on single product page

I'm working on a child theme where I want to split variable product into 2 elements:
Regular variation form with a dropdown where customer gets to pick from a single attribute with multiple terms except for one.
A single form with just one specific term and its own add to cart button.
For example:
When selling clothes we create "tshirts" attribute and use terms to describe both the ones that have prints on them (print 1, print 2, print3 etc.) as well as a regular, plain tshirt (which has a special "plain-shirt" term) and unlike others - doesn't appear in the dropdown but is a standalone element.
Attached image
I've tried looking into different solutions and eventually settled down on editing variable.php themplate, duplicating the variations_form and using code from this thread: Hide specific product attribute terms on WooCommerce variable product dropdown to filter out necessary terms. However, since 'wc_dropdown_variation_attribute_options' fucntion and hooks are already inside the form I'm struggling with how should I go about this. It is probably an extremely wonky approach in my case so any help, ideas and suggestions will be greatly appreciated.
Edit: Found a working soultion by further editing variable.php template:
For the first form I added a filter before "woocommerce_before_variations_form" hook:
add_filter( 'woocommerce_dropdown_variation_attribute_options_args', 'sample_dropdown', 10, 1 );
function sample_dropdown( $args ) {
$taxonomy = 'pa_capacity';
$targeted_terms_names = array( "plain-shirt", "plain-tshirt" );
$terms_slugs = array_filter( array_map( 'sanitize_title', $targeted_terms_names ) );
if( $args['attribute'] === $taxonomy ) {
foreach( $args['options'] as $key => $option ){
if( ! in_array( $option , $terms_slugs ) ) {
unset($args['options'][$key]);
}
}
}
return $args;
}
and removed filer on "woocommerce_after_variations_form" hook.
Then for the second form I applied another filter with reversed array
if( in_array( $option , $terms_slugs )
Instead of
if( ! in_array( $option , $terms_slugs ) )
Its' still very untidy but at least it works.

WooCommerce - Suffix Only Gets Applied To Product If It Has A Sales Price

I'm using the code below to output a suffix on a WooCommerce site:
add_filter( 'woocommerce_get_price_suffix', 'price_suffix', 10, 1 );
function price_suffix( $product ){
if ( has_term( 'vinylflooring', 'product_cat' ) ) {
$suffix = ' per sqm';
update_option( 'woocommerce_price_display_suffix', $suffix );
return $suffix;
}
}
This works to an extent but for variable products that have no sale price, the suffix is not output.
If I add a sale price to the variation, the suffix is output, but I want it to display without one.
Any idea what may be causing this behaviour?
Thanks

WooCommerce - Add Suffix To Price On Products With Variations

I have the following code to add a suffix to carpet product prices:
add_filter( 'woocommerce_get_price_suffix', 'price_suffix', 10, 1 );
function price_suffix( $product ){
if ( has_term( 'carpet', 'product_cat' ) ) {
$suffix = ' per sqm';
update_option( 'woocommerce_price_display_suffix', $suffix );
return $suffix;
}
}
This does work but for some reason it is ignoring the products that have a variation.
On the products that have a variation, the price is always the same so I would like it to work in exactly the same manner.
Can anyone point me in the direction of how to do this please

Set Discounted Price for Related Product on Product Page

I am trying to set the price of all related products on the products page to 10% less = 0.9
The goal is to provide a discount of all related products on the product page but when viewed as a product, give the normal price.
Overall, the idea is to provide incentive that generates up-selling of related products.
I am asking for two things here. ONE: change the product price for related products on the product page (10% off) and TWO: carry that discounted price into the cart and checkout when the related discounted product is added to cart from the product page.
I almost got the first part down, but the code I'm trying to get working is giving me an error saying:
Warning: A non-numeric value encountered
My code so far:
add_filter( 'woocommerce_get_price_html', 'related_product_price_discount', 100, 2 );
function related_product_price_discount( $price, $product ) {
global $woocommerce_loop;
// make sure this is a related product on product page
if( is_product() && $woocommerce_loop['name'] == 'related' ){
$price = $price * 0.9;
}
// return related product price with discount
return apply_filters( 'woocommerce_get_price', $price );
}
The rule in StackOverFlow is one question at the time, so I will answer only your first question, which is related to your code issue...
Note that the hook woocommerce_get_price_html is related to the displayed formatted price.
To avoid the error "Warning: A non-numeric value encountered", you will use the following:
add_filter( 'woocommerce_get_price_html', 'related_product_price_discount', 100, 2 );
function related_product_price_discount( $price_html, $product ) {
global $woocommerce_loop;
// make sure this is a related product on product page
if( is_product() && $woocommerce_loop['name'] == 'related' ){
$price_html = wc_price( wc_get_price_to_display( $product ) * 0.9 );
}
// return related product displayed discounted formatted price
return $price_html;
}
Code goes in functions.php file of your active child theme (active theme). Tested and works.

Create a Woocommerce product sold in units of gram

I would like to create a product in WooCommerce that is sold in units of gram.
The customer would enter the number of grams they want (in an input field) on the product page, and the price would be computed on the fly and added to the cart.
My question is: is this possible, and if so, can someone give me just a "big picture" idea of how I would implement it?
I don't need line-by-line code, just hoping someone with more knowledge of the structure of Woo can guide me on how to best attack the problem.
I already have parts of it worked out:
I can decide that the price entered for the product is the price per
100 grams, so that is how the seller will enter the price.
Then I can
write a little bit of Javascript to compute the price on the fly and
display it on the page as the user types the amount they want. No
problem.
But... I think every discrete product in Woo needs to have its own price.. So for example, if a customer wants 123g of a product, it seems like I might have to create a variation on the fly for that specific price/amount, and then add that to the cart. Which (judging by this) looks non-trivial and a little hacky. Is there a better way to do this?
WooCommerce has an option to show the weights as grams.
The following code will display the KG weights as grams on the WooCommerce templates :
// Convert the product weight
function ag_woocommerce_product_get_weight( $weight ) {
// Only convert if we have a weight
if ($weight) {
// The weight is in KGS, and we want grams, to multiple by 1000
$weight = $weight * 1000;
}
return $weight;
};
// add the filter
add_filter( 'woocommerce_product_get_weight', 'ag_woocommerce_product_get_weight', 10, 1 );
Hope this might help. Cheers!
There is a free plugin for WooCommerce that allows you to input a unit of measure (UOM) for each product:
https://wordpress.org/plugins/woocommerce-unit-of-measure/
I found this plugin that does pretty much exactly what I need-- https://woocommerce.com/products/measurement-price-calculator/
It's easier and quicker to give you that real example, than explain step by step… You will see which hooks are used for all steps or tasks.
You dont need variable products or generate a variation on the fly.
You just need to set on each simple product the price for one gram (or any other base). Now in this code, you can target those products with:
an array of product Ids
or by product categories (or even product tags).
Your concern is about the way to pass the data in the cart, to update the final price for each product and display the chosen grams amount in cart, checkout and in the order.
So in each product you will only set the price by gram… (or you can also make changes in the code and set the product price for 100 grs or even any other base).
The code:
// Add a product custom field "grams_quantity" that will update the displayed price
add_action('woocommerce_before_add_to_cart_button', 'special_product_by_grams', 25);
function special_product_by_grams(){
global $product;
// HERE Define the special product IDs sold by grams
$targeted_product_ids = array(37);
// or HERE Define a product categories (ids, slugs or names)
$categories = array('sold-by-gram');
// Only for products sold by gram
$product_id = $product->get_id();
if ( ! ( in_array( $product_id, $targeted_product_ids ) || has_term( $categories, 'product_cat', $product_id ) ) ) return;
?>
<div class="grams-field">
<label for="grams_quantity"><?php _e('Grams: ','woocoomerce'); ?><span></span><br>
<input type="number" step="1" name="grams_quantity" class="grams_quantity" id="grams_quantity" value="1">
</label>
</div><br>
<script type="text/javascript">
(function($){
// variables initialization
var priceByGram = <?php echo wc_get_price_to_display( $product ); ?>,
currencySymbol = $(".woocommerce-Price-currencySymbol").html(),
updatedPrice;
// On live event: imput number fields
$('input#grams_quantity').on( "click blur", function(){
updatedPrice = ($(this).val() * priceByGram).toFixed(2);
$(".woocommerce-Price-amount.amount").html('<span class="woocommerce-Price-amount amount">'+updatedPrice+' '+currencySymbol+'</span>');
console.log("event"); // <== To be removed
});
})(jQuery);
</script>
<?php
}
// Save the "grams_quantity" custom product field data in Cart item
add_filter( 'woocommerce_add_cart_item_data', 'save_in_cart_the_custom_product_field', 10, 2 );
function save_in_cart_the_custom_product_field( $cart_item_data, $product_id ) {
if( isset( $_POST['grams_quantity'] ) ) {
$cart_item_data[ 'grams_quantity' ] = $_POST['grams_quantity'];
// When add to cart action make an unique line item
$cart_item_data['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'custom_data', $_POST['grams_quantity'] );
}
return $cart_item_data;
}
// Update product price by grams in cart and checkout
add_filter( 'woocommerce_before_calculate_totals', 'update_prices_by_gram', 10, 1 );
function update_prices_by_gram( $cart_object ) {
// HERE Define the special product IDs sold by grams
$targeted_product_ids = array(37);
// or HERE Define a product categories (ids, slugs or names)
$categories = array('sold-by-gram');
foreach ( $cart_object->get_cart() as $cart_item ) {
// Only for products sold by gram
$product_id = $cart_item['product_id'];
if ( in_array( $product_id, $targeted_product_ids ) || has_term( $categories, 'product_cat', $product_id ) ){
// Get an instance of the WC_Product object and the
$product = $cart_item['data'];
$grams = $cart_item['grams_quantity'];
// Method is_on_sale() manage everything (dates…)
$product->set_price( $product->get_price() * $grams);
}
}
}
// Render "grams_quantity" the custom product field in cart and checkout
add_filter( 'woocommerce_get_item_data', 'render_product_custom_field_meta_on_cart_and_checkout', 10, 2 );
function render_product_custom_field_meta_on_cart_and_checkout( $cart_data, $cart_item ) {
$custom_items = array();
if( !empty( $cart_data ) )
$custom_items = $cart_data;
if( isset( $cart_item['grams_quantity'] ) )
$custom_items[] = array(
'name' => __( 'Grams', 'woocommerce' ),
'value' => sanitize_text_field( $cart_item['grams_quantity'] ),
'display' => sanitize_text_field( $cart_item['grams_quantity'] ),
);
return $custom_items;
}
// Save "grams_quantity" to the order items meta data
add_action('woocommerce_add_order_item_meta','add_product_custom_fiel_to_order_item_meta', 1, 3 );
function add_product_custom_fiel_to_order_item_meta( $item_id, $item_values, $item_key ) {
if( isset( $item_values['grams_quantity'] ) )
wc_update_order_item_meta( $item_id, 'Grams', sanitize_text_field( $item_values['grams_quantity'] ) );
}
Code goes in function.php file of your active child theme (or active theme) or in any plugin file.
Tested and works.

Resources