Woocommerce Show default variation price - wordpress

I'm using Woocommerce and product variations and all my variations have a default variation defined.
How I can find the default variation and display its price?
This is the code I got so far, but it displays the cheapest variation price, and I'm looking for my default variation product price instead.
// Use WC 2.0 variable price format, now include sale price strikeout
add_filter( 'woocommerce_variable_sale_price_html', 'wc_wc20_variation_price_format', 10, 2 );
add_filter( 'woocommerce_variable_price_html', 'wc_wc20_variation_price_format', 10, 2 );
function wc_wc20_variation_price_format( $price, $product ) {
// Main Price
$prices = array( $product->get_variation_price( 'min', true ), $product->get_variation_price( 'max', true ) );
$price = $prices[0] !== $prices[1] ? sprintf( __( 'HERE YOUR LANGUAGE: %1$s', 'woocommerce' ), wc_price( $prices[0] ) ) : wc_price( $prices[0] );
// Sale Price
$prices = array( $product->get_variation_regular_price( 'min', true ), $product->get_variation_regular_price( 'max', true ) );
sort( $prices );
$saleprice = $prices[0] !== $prices[1] ? sprintf( __( 'HERE YOUR LANGUAGE: %1$s', 'woocommerce' ), wc_price( $prices[0] ) ) : wc_price( $prices[0] );
if ( $price !== $saleprice ) {
$price = '<del>' . $saleprice . '</del> <ins>' . $price . '</ins>';
}
return $price;
I found the code example here Woocommerce variation product price to show default

I did not find answer for this question (how to display price from default product variation instead of price range?) so i created the code:
add_filter('woocommerce_variable_price_html', 'custom_variation_price', 10, 2);
function custom_variation_price( $price, $product ) {
foreach($product->get_available_variations() as $pav){
$def=true;
foreach($product->get_variation_default_attributes() as $defkey=>$defval){
if($pav['attributes']['attribute_'.$defkey]!=$defval){
$def=false;
}
}
if($def){
$price = $pav['display_price'];
}
}
return woocommerce_price($price);
}
This plugin show price from default variation, of course if you set default values before. Tested on woocommerce version 2.6.2.

This is my own solution, think it could be better, but I'm not a php developer, so feel free to add improvements.
function wc_wc20_variation_price_format( $price, $product ) {
// Main Price
$available_variations = $product->get_available_variations();
$selectedPrice = '';
foreach ( $available_variations as $variation )
{
$tmp = implode($variation['attributes']);
if (strpos($tmp,'standard') !== false) {
$selectedproduct = wc_get_product($variation['variation_id']);
$price = $selectedproduct->get_price();
$selectedPrice = wc_price($price);
}
}
return $selectedPrice;
}

I modified your code a bit to show discounted price as well.
// show default variation price
add_filter('woocommerce_variable_price_html', 'custom_variation_price', 10, 2);
function custom_variation_price( $price, $product ) {
$default_attributes = $product->get_variation_default_attributes();
foreach($product->get_available_variations() as $variation) {
$is_default=true;
foreach($default_attributes as $attribute_key => $attribute_value) {
if($variation['attributes']['attribute_' . $attribute_key] != $attribute_value){
$is_default=false;
break;
}
}
if($is_default){
return $variation['price_html'];
}
}
}

Related

Create a custom hidden field in backend product pages and use value in WooCommerce products sort by

I am making an e-commerce website using WooCommerce. With the help of this forum, I was able to code some useful snippets. However, I am stuck at a certain code now.
I have pieced together codes from various sections, but I am unable to get it to work.
What I want to do - create a custom hidden field programmatically for discount percent & then use the field to allow sorting by discount.
But it looks like the meta does not save in the backend.
When I sort by discount, all I get is this 'No products were found matching your selection.' even though there are some products on sale.
This is my code:
//add_action ('woocommerce_process_product_meta', 'mycode_product_save_discount');
add_action ('woocommerce_admin_process_product_object', 'mycode_product_save_discount');
function mycode_product_save_discount ($product)
{
$product = wc_get_product ($product);
$regular_price = (float) $product->get_regular_price();
$sale_price = (float) $product->get_sale_price();
if (!empty($sale_price))
{
$discount_percent = round (100 - ($sale_price / $regular_price * 100), 4);
$discount_percent = $_POST['_discount_percent'][$product];
//update_post_meta ($post_id, '_discount_percent', $discount_percent);
$product->update_meta_data ('discount_percent', $discount_percent);
$product->save();
}
}
add_filter ('woocommerce_get_catalog_ordering_args', 'mycode_add_discount_to_ordering_args');
function mycode_add_discount_to_ordering_args ($args)
{
$orderby_value = isset ($_GET['orderby']) ? wc_clean ($_GET['orderby']) : apply_filters ('woocommerce_default_catalog_orderby', get_option ('woocommerce_default_catalog_orderby'));
if (!is_post_type_archive ('product') && !is_shop() && isset($args['orderby']))
{
$orderby_value = $sort_args['orderby'];
}
if ('discount' == $orderby_value)
{
$args['orderby'] = 'meta_value_num';
$args['order'] = 'DESC';
$args['meta_key'] = '_discount_percent';
}
return $args;
}
add_filter ('woocommerce_default_catalog_orderby_options', 'mycode_add_discount_to_orderby');
add_filter ('woocommerce_catalog_orderby', 'mycode_add_discount_to_orderby');
function mycode_add_discount_to_orderby ($sortby)
{
$sortby['discount'] = 'Sort by discount';
return $sortby;
}
What do I need to change to make it work?
You are close, but your code contains some minor mistakes.
This should suffice:
/*** For debugging purposes, remove this action hook if everything works!! ***/
function action_woocommerce_product_options_general_product_data() {
// Text field
woocommerce_wp_text_input( array(
'id' => '_discount_percent',
'label' => __( 'Discount percent', 'woocommerce' ),
'placeholder' => '',
'description' => __( 'For debugging purposes, remove this action hook if everything works', 'woocommerce' ),
'desc_tip' => true,
'custom_attributes' => array( 'readonly' => true ),
));
}
add_action( 'woocommerce_product_options_general_product_data', 'action_woocommerce_product_options_general_product_data', 10, 0 );
/*** From here on the code below is needed so that everything would work smoothly ***/
// Save value
function action_woocommerce_admin_process_product_object( $product ) {
// Getters
$regular_price = (float) $product->get_regular_price();
$sale_price = (float) $product->get_sale_price();
// NOT empty
if ( ! empty( $sale_price ) ) {
// Calculate
$discount_percent = round( 100 - ( $sale_price / $regular_price * 100 ), 4 );
// Update
$product->update_meta_data( '_discount_percent', $discount_percent );
}
}
add_action( 'woocommerce_admin_process_product_object', 'action_woocommerce_admin_process_product_object', 10, 1 );
// Ordering products based on the selected values
function filter_woocommerce_get_catalog_ordering_args( $args, $orderby, $order ) {
switch( $orderby ) {
case 'discount':
$args['orderby'] = 'meta_value';
$args['order'] = 'ASC';
$args['meta_key'] = '_discount_percent';
break;
}
return $args;
}
add_filter( 'woocommerce_get_catalog_ordering_args', 'filter_woocommerce_get_catalog_ordering_args', 10, 3 );
// Orderby setting
function filter_orderby( $orderby ) {
$orderby['discount'] = __( 'Sort by discount', 'woocommerce' );
return $orderby;
}
add_filter( 'woocommerce_default_catalog_orderby_options', 'filter_orderby', 10, 1 );
add_filter( 'woocommerce_catalog_orderby', 'filter_orderby', 10, 1 );
This shows the value after it has been saved. This is not actually necessary, but can be useful for debug purposes.

Woocommerce $product->is_on_sale() always returns true

I have the code below in functions.php for a child theme. The idea is that if a user books a job online they get a discount on the job to encourage more online bookings and is showing like this in the store:
Walk-In Price: £349.99
Online Price: £339.00
However, $product->is_on_sale() always seems to return true even if I leave the Sale Price blank in the product. If I only have a normal price (no sale price) then this displays nothing (i.e no price is shown, its left blank) and I want to show the normal price.
// ***********************************************************
// START ADD TEXT BEFORE SALE PRICE
// && (!has_term( 'product', 'product_cat'))
// ***********************************************************
function bd_rrp_sale_price_html( $price, $product ) {
// SHOWS PRICE FOR PRODUCTS NOT REPAIRS
if (has_term( 'Products', 'product_cat'))
{
if ( $product->is_on_sale() )
{
$has_sale_text = array(
'<del>' => '<del>Normal Price: ',
'<ins>' => '<br>Sale Price: <ins>' );
$return_string = str_replace(array_keys( $has_sale_text ), array_values( $has_sale_text ), $price);
}
else
{
$return_string = $price;// . get_woocommerce_currency_symbol().$product->get_regular_price();
}
}
else
{
if ( $product->is_on_sale() )
{
$has_sale_text = array(
'<del>' => '<del>Walk-In Price: ',
'<ins>' => '<br>Online Price: <ins>'
);
$return_string = str_replace(array_keys( $has_sale_text ), array_values( $has_sale_text ), $price);
}
else
{
$retun_string = "2";// $price;
}
}//ENDIF
return $return_string;
}
add_filter( 'woocommerce_get_price_html', 'bd_rrp_sale_price_html', 100, 2 );

Woocommerce - Calculate Exta Fee Based on Amount of People

I've added in a function for a custom field on the product general options:
// Add Custom Field to Product under General
function create_extra_fee_field() {
$args = array(
'id' => 'park_fee',
'label' => __( 'Natl Park Entrance Fee', 'tranq-lsx-child' ),
'class' => 'tranq-custom-field',
'desc_tip' => true,
'description' => __( 'This sets the Fee that will be added to the car.', 'tranq-lsx-child' ),
);
woocommerce_wp_text_input( $args );
}
add_action( 'woocommerce_product_options_general_product_data', 'create_extra_fee_field' );
// Save Custom Field Data
function save_extra_fee_field( $post_id ) {
$product = wc_get_product( $post_id );
$title = isset( $_POST['park_fee'] ) ? $_POST['park_fee'] : '';
$product->update_meta_data( 'park_fee', sanitize_text_field( $title ) );
$product->save();
}
add_action( 'woocommerce_process_product_meta', 'save_extra_fee_field' );
I would like to add this as an extra fee to the Cart Totals which multiplied based on the amount of Person/People that were selected from the Woocommerce Bookings.
Something like this:
// Calculate Extra Fee Based on Amount of People.
add_action('woocommerce_cart_calculate_fees' , 'add_custom_fees');
function add_custom_fees( WC_Cart $cart ){
$park_fee = get_post_meta($item['product_id'] , 'park_fee', true);
foreach( $cart->get_cart() as $item ){
$fees += $item[ 'park_fee' ] * 14706;
}
if( $fees != 0 ){
$cart->add_fee( 'Park Fee', $fees);
}
}
How do I go about in achieving this? Any Links to a walkthrough would be greatly appreciated.
I've added this and it seems to work:
// Add Custom Field to Cart Totals
function woo_add_cart_fee() {
global $woocommerce;
foreach( WC()->cart->get_cart() as $cart_item ){
// Get the WC_Product object (instance)
$product = $cart_item['data'];
$product_id = $product->get_id(); // get the product ID
$custom_field_value = get_post_meta( $product->get_id(), 'park_fee', true );
$person = array_sum( $cart_item['booking']['_persons'] );
}
$additional_fee_name = "Natl Park Entrance Fee";
$extra_fee = $custom_field_value * $person;
$addedFee = false;
// first check to make sure it isn’t already there
foreach ( $woocommerce->cart->get_fees() as $_fee )
{
if ($_fee->id == sanitize_title($additional_fee_name) )
{
$_fee->amount = (float) esc_attr( $extra_fee );
}
}
if (!$addedFee)
{
$woocommerce->cart->add_fee( __($additional_fee_name, "woocommerce"),
$extra_fee, $additional_fee_taxable );
}
}
add_action( "woocommerce_before_calculate_totals", "woo_add_cart_fee" );

Woocommerce - Not to show variable price range [duplicate]

On WooCommerce, I would like to change the Variable single product page layout. Because when you have an variable product you get this wired price rage (below product title) in the Variable Product page and it shows in the shop page as well.
For me, the standard way is to show the lowest price of the product in the shop as well as product page and change that price according to user selection of variables. I can't believe why.
I can remove the price range and show the lowest price using this code snippet.
https://businessbloomer.com/disable-variable-product-price-range-woocommerce/
But then again, that lowest price doesn't change according to select variables. There are again two prices in the variable product layout. This is my current variable product page layout
http://www.preorders.lk/product/beats-solo3-wireless-on-ear-headphones/
So, can anyone please help to remove the price range from the variable product page and show only one lowest price ( under the product title) of the product as default. So that price should be change according to the variables which that product have. And that lowest price should be show in the shop page as well.
Here's a screenshot:
2021 definitive update
Works for WooCommerce 4+ and 5+ available on:
Replace the Variable Price range by the chosen variation price in WooCommerce 4+
Update (December 2017): to avoid, Problems regarding non variable products in some themes and a repetition availability bug in some themes
Note: Some plugins like the German Market or some themes will not work with this code, as they make their own changes in the hooks or in the html structure.
This is completely possible.
First we remove the unwanted price.
We output instead the variable price without the price range and show the lowest price.
We make a copy of this variable price in a hidden container (to be used/read by our jQuery script)
Then we hide the containers of chosen variation price (and the stock availability)
With the help of our jQuery script, when we get the chosen variation price, we replace the variable price (and display the stock availability).
If the customer change of variation we update the price... If the variation price is not displayed during that change process, our variable price is displayed
Here is that code:
add_action( 'woocommerce_before_single_product', 'move_variations_single_price', 1 );
function move_variations_single_price(){
global $product, $post;
if ( $product->is_type( 'variable' ) ) {
// removing the variations price for variable products
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
// Change location and inserting back the variations price
add_action( 'woocommerce_single_product_summary', 'replace_variation_single_price', 10 );
}
}
function replace_variation_single_price(){
global $product;
// Main Price
$prices = array( $product->get_variation_price( 'min', true ), $product->get_variation_price( 'max', true ) );
$price = $prices[0] !== $prices[1] ? sprintf( __( 'From: %1$s', 'woocommerce' ), wc_price( $prices[0] ) ) : wc_price( $prices[0] );
// Sale Price
$prices = array( $product->get_variation_regular_price( 'min', true ), $product->get_variation_regular_price( 'max', true ) );
sort( $prices );
$saleprice = $prices[0] !== $prices[1] ? sprintf( __( 'From: %1$s', 'woocommerce' ), wc_price( $prices[0] ) ) : wc_price( $prices[0] );
if ( $price !== $saleprice && $product->is_on_sale() ) {
$price = '<del>' . $saleprice . $product->get_price_suffix() . '</del> <ins>' . $price . $product->get_price_suffix() . '</ins>';
}
?>
<style>
div.woocommerce-variation-price,
div.woocommerce-variation-availability,
div.hidden-variable-price {
height: 0px !important;
overflow:hidden;
position:relative;
line-height: 0px !important;
font-size: 0% !important;
}
</style>
<script>
jQuery(document).ready(function($) {
$('select').blur( function(){
if( '' != $('input.variation_id').val() ){
if($('p.availability'))
$('p.availability').remove();
$('p.price').html($('div.woocommerce-variation-price > span.price').html()).append('<p class="availability">'+$('div.woocommerce-variation-availability').html()+'</p>');
console.log($('input.variation_id').val());
} else {
$('p.price').html($('div.hidden-variable-price').html());
if($('p.availability'))
$('p.availability').remove();
console.log('NULL');
}
});
});
</script>
<?php
echo '<p class="price">'.$price.'</p>
<div class="hidden-variable-price" >'.$price.'</div>';
}
Code goes in any php file of your active child theme (or theme) or also in any plugin php file.
This code is tested and works on WooCommerce 3.2.x (should work on WooCommerce 2.6.x too)
You can optionally move the CSS (<style></style>) to the styles.css file of your active child theme (or active theme) and then remove it from this function…
Related:
Move the variation price location in WooCommerce
Late to the party but I was looking for a more dynamic/universal solution and less code so I adjusted the answer to the following.
The price is updated based on the variation-form triggers so the styling and original HTML is maintained.
add_action( 'woocommerce_before_single_product', 'move_variations_single_price', 1 );
function move_variations_single_price(){
global $product, $post;
if ( $product->is_type( 'variable' ) ) {
add_action( 'woocommerce_single_product_summary', 'replace_variation_single_price', 10 );
}
}
function replace_variation_single_price() {
?>
<style>
.woocommerce-variation-price {
display: none;
}
</style>
<script>
jQuery(document).ready(function($) {
var priceselector = '.product p.price';
var originalprice = $(priceselector).html();
$( document ).on('show_variation', function() {
$(priceselector).html($('.single_variation .woocommerce-variation-price').html());
});
$( document ).on('hide_variation', function() {
$(priceselector).html(originalprice);
});
});
</script>
<?php
}
Successfully tested with v4.0.1. As long as themes/plugins don't change the markup it should work. If not you can easily change the priceselector accordingly.
I'm aware that I am resurrecting an old thread here, but something I discovered when using this code is that you need to be aware that with this code as is you risk stopping single, non-variable prices from displaying on some themes as:
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
is triggered on all product pages, regardless of it being a variable product or not.
You can use the below version which simply checks if the current product is variable or not before running the rest of the code.
add_action( 'woocommerce_before_single_product', 'check_if_variable_first' );
function check_if_variable_first(){
if ( is_product() ) {
global $post;
$product = wc_get_product( $post->ID );
if ( $product->is_type( 'variable' ) ) {
// removing the price of variable products
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
// Change location of
add_action( 'woocommerce_single_product_summary', 'custom_wc_template_single_price', 10 );
function custom_wc_template_single_price(){
global $product;
// Variable product only
if($product->is_type('variable')):
// Main Price
$prices = array( $product->get_variation_price( 'min', true ), $product->get_variation_price( 'max', true ) );
$price = $prices[0] !== $prices[1] ? sprintf( __( 'From: %1$s', 'woocommerce' ), wc_price( $prices[0] ) ) : wc_price( $prices[0] );
// Sale Price
$prices = array( $product->get_variation_regular_price( 'min', true ), $product->get_variation_regular_price( 'max', true ) );
sort( $prices );
$saleprice = $prices[0] !== $prices[1] ? sprintf( __( 'From: %1$s', 'woocommerce' ), wc_price( $prices[0] ) ) : wc_price( $prices[0] );
if ( $price !== $saleprice && $product->is_on_sale() ) {
$price = '<del>' . $saleprice . $product->get_price_suffix() . '</del> <ins>' . $price . $product->get_price_suffix() . '</ins>';
}
?>
<style>
div.woocommerce-variation-price,
div.woocommerce-variation-availability,
div.hidden-variable-price {
height: 0px !important;
overflow:hidden;
position:relative;
line-height: 0px !important;
font-size: 0% !important;
}
</style>
<script>
jQuery(document).ready(function($) {
$('select').blur( function(){
if( '' != $('input.variation_id').val() ){
$('p.price').html($('div.woocommerce-variation-price > span.price').html()).append('<p class="availability">'+$('div.woocommerce-variation-availability').html()+'</p>');
console.log($('input.variation_id').val());
} else {
$('p.price').html($('div.hidden-variable-price').html());
if($('p.availability'))
$('p.availability').remove();
console.log('NULL');
}
});
});
</script>
<?php
echo '<p class="price">'.$price.'</p>
<div class="hidden-variable-price" >'.$price.'</div>';
endif;
}
}
}
}

How to show Product Price + Shipping VAT in "Total" Merged

I have one little isusue that dont know how to resolve myself. I have set in my shop to show separated Price and shipping costs but in total showed me bad price.
For example my products cost 24.99€ + SHIPPING FEE : 3,95€ = 28.94€ but in calculation in cart page is calculating: 24.99€ + 3.95€ - 0.26€ what is wrong.
i found that Total price is calculated via this function:
<td data-title="<?php esc_attr_e( 'Total', 'woocommerce' ); ?>"><?php wc_cart_totals_order_total_html(); ?></td>
and this is function that control that part:
from cart-totals.php in templates, and bellow is function from wc-cart-functions.php
function wc_cart_totals_order_total_html() {
$value = '<strong>' . WC()->cart->get_total() . '</strong> ';
// If prices are tax inclusive, show taxes here.
if ( wc_tax_enabled() && WC()->cart->display_prices_including_tax() ) {
$tax_string_array = array();
$cart_tax_totals = WC()->cart->get_tax_totals();
if ( get_option( 'woocommerce_tax_total_display' ) == 'itemized' ) {
foreach ( $cart_tax_totals as $code => $tax ) {
$tax_string_array[] = sprintf( '%s %s', $tax->formatted_amount, $tax->label );
}
} elseif ( ! empty( $cart_tax_totals ) ) {
$tax_string_array[] = sprintf( '%s %s', wc_price( WC()->cart->get_taxes_total( true, true ) ), WC()->countries->tax_or_vat() );
}
if ( ! empty( $tax_string_array ) ) {
$taxable_address = WC()->customer->get_taxable_address();
$estimated_text = WC()->customer->is_customer_outside_base() && ! WC()->customer->has_calculated_shipping()
? sprintf( ' ' . __( 'estimated for %s', 'woocommerce' ), WC()->countries->estimated_for_prefix( $taxable_address[0] ) . WC()->countries->countries[ $taxable_address[0] ] )
: '';
$value .= '<small class="includes_tax">' . sprintf( __( '(includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) . $estimated_text ) . '</small>';
}
}
echo apply_filters( 'woocommerce_cart_totals_order_total_html', $value );
}
So my question is how to add that 1.63E at Total Price, so will get correct price. Thanks
EDIT: Found the same problem like mine here but answers dont seems to make changes.
First, thanks for your Post, I was almost thinking I'm the only one with this need.
So far, this worked for my shop. I'm shure my code is not very versatile for different shop settings. Maybe someone could make a more general usable version.
Edit: I've added a picture showing the two rates. Image of the result and I've found a minor mistake calculating the shipping tax, corrected now.
/**
* Change Tax Amount including Shipping Taxes
* Referencing to wc-cart-functions.php starting from Line 296
*
*/
add_filter( 'woocommerce_cart_totals_order_total_html', 'woo_rename_tax_inc_cart', 10, 1 );
function woo_rename_tax_inc_cart( $value ) {
/* Get all infos needed */
$shipping_total = WC()->cart->shipping_total;
$taxes = WC()->cart->get_taxes_total( true, true );
$taxrate = 7.7;
$newtaxes = ($shipping_total/(100+$taxrate)*$taxrate) + $taxes; // Shipping is 100% + taxrate %, so we deduct both percentages.
/* Check if Shipment total is active */
if ( ! empty($shipping_total) && $shipping_total != 0 ) {
if ( ! empty( $value ) ) {
// Show Price /wc-cart-functions.php Line 297
$value = '<strong>' . WC()->cart->get_total() . '</strong> ';
$value .= '<small class="includes_tax">' . '(inkl. ' . wc_price( $newtaxes ) . ' MWST)' . '</small>';
}
}
// Attach Tax Info to Price (single line)
$value = str_ireplace( 'Tax', 'GST', $value );
return $value;
}

Resources