Woocommerce variable product stock qty message - woocommerce

Is there a way to change variable product default stock message?
My goal is to check how many items are in stock, if there is more than 20 items it should display "More than 20 available" and if it is under 20 items, it says exactly how much items are left (15 items left)
Is it doable?
I have googled the hell out of it but no luck.

add_filter( 'woocommerce_get_availability', 'custom_get_availability', 1, 2);
function custom_get_availability( $availability, $_product ) {
if ( $_product->product_type == 'variation' && $_product->manage_stock == "yes" && $_product->stock > 20 ) $availability['availability'] = 'more than 20';
return $availability;
}

Related

Woocommerce Product Price 3 decimals, all Other Prices 2 Decimals

Hello to all!
I'm new here and already have my first question.
i have a woocommerce project where i need the single product prices with 3 decimals - and all other prices (subtotal, total, tax) should be with 2 decimals (rounded) - also in the e-mails this prices should have 2 decimals.is there a simple function for this or a work around? Thanks for the help!
Stefan
) Just found a way and wanted to share with you:
Select in the woocommerce settings the 2 decimals for the shop.
then add this to the function.php of your theme:
add_filter( 'wc_get_price_decimals' , 'custom_price_decimals', 20, 1 );
function custom_price_decimals( $decimals ) {
if( is_product() || is_shop() || is_product_category() || is_product_tag() )
$decimals = 3;
return $decimals;
}

get product variation parent product

How I can get variation parent product ID.
EXAMPLE:
I have product with ID 35
and this product has two variations colors - red (ID 351), black (ID 352)
My code:
$product = wc_get_product(get_the_ID()); //get_the_ID() is ID 351 and I need this parent ID 35
The proper way
As LoicTheAztec suggested in comments, you should use this:
$parent_product = wc_get_product($product->get_parent_id());
The reason why you should retrieve parent product via get_parent_id() is that it will trigger hook woocommerce_product_variation_get_parent_id and it will be easily modifiable by other plugins/themes:
add_filter('woocommerce_product_variation_get_parent_id', function($value, $wc_data) {
// ...
return $value;
}, 10, 2);
This will also work, but it won't trigger WC-specific hooks:
$parent_product_id = wp_get_post_parent_id($product->get_id());
$parent_product = wc_get_product($parent_product_id);
Old answer
Note: That's not working outside the loop and will always return 0 if you attempt to substitute get_the_ID() with $product->id - in that case use $product->get_id() as in the example above.
Use wp_get_post_parent_id, as variations have their parent as the product itself.
Example:
$variation_id = get_the_ID();
$product_id = wp_get_post_parent_id($variation_id);
Never use WC_Product::get_parent():
$parent_product = $product->get_parent(); // will always return '0

how to get woocommerce coupon discount to calculate from the lowest priced item first

Woocommerce coupon % discount when applied with limit to x quantity items, calculate the discount starting from the highest priced items instead of the lowest priced items.
I am trying to change this default setting so that the coupon discounts can be calculated from the lowest priced items. I found this Finding Lowest Price in Woocommerce Cart Items but the code is outdated which caused php error.
I have found that the code is in reference from class-wc-discounts.php
$coupon_amount = $coupon->get_amount();
foreach ( $items_to_apply as $item ) {
// Find out how much price is available to discount for the item.
$discounted_price = $this->get_discounted_price_in_cents( $item );
// Get the price we actually want to discount, based on settings.
$price_to_discount = ( 'yes' === get_option( 'woocommerce_calc_discounts_sequentially', 'no' ) ) ? $discounted_price : round( $item->price );
// See how many and what price to apply to.
$apply_quantity = $limit_usage_qty && ( $limit_usage_qty - $applied_count ) < $item->quantity ? $limit_usage_qty - $applied_count : $item->quantity;
$apply_quantity = max( 0, apply_filters( 'woocommerce_coupon_get_apply_quantity', $apply_quantity, $item, $coupon, $this ) );
$price_to_discount = ( $price_to_discount / $item->quantity ) * $apply_quantity;
Can anyone offer any help and shed some guidance?
after hours of looking through the codes, the answer was indeed in class-wc-discounts.php
This is the original code:
/**
* Sort by price.
*
* #since 3.2.0
* #param array $a First element.
* #param array $b Second element.
* #return int
*/
protected function sort_by_price( $a, $b ) {
$price_1 = $a->price * $a->quantity;
$price_2 = $b->price * $b->quantity;
if ( $price_1 === $price_2 ) {
return 0;
}
return ( $price_1 < $price_2 ) ? 1 : -1;
}
So I simply changed this line ( $price_1 < $price_2 ) ? 1 : -1; to ( $price_1 < $price_2 ) ? -1 : 1; which then makes the sorting from the lowest price to the highest.
not sure if this is the best trick, but problem solved..

Issue with Easy Booking plugin and Woocommerce

We are using the Easy Booking plugin for a client’s project and they want the ability to make the dates recurring. I.E they use the calendar to book Mon, Tues and Wed and want to have it recurring for the next 3 weeks.
We added some JS functionality, with a few form fields, that modifys the data-booking_price so that it is the price * recurring modifier. The order flow works fine while the quantity is one, but if we increase the quantity, the whole thing breaks apart. After we add the item to the cart and then go to View Cart, the price is set to the original booking price, sans the modifier.
You can view it in action here: http://bethpark.dev.ksand.com/product/meter-bags
My question is how does how does the plugin pass the total of the product along to the cart? From what I can see, it’s not updating Woo Sessions with the total that is getting generated. Is that not accurate? I realize we are modifying how the plugin inherenly works, but any sort of pointing in the right direction would be much appreciated!
-Anthony
I've updated WC()->cart->total on both the cart page and the checkout page, but it keeps getting overwritten. I've also manually set the total in WC()->sessions but that also get's overwritten (I've since commented these out since this felt extremely hacky.)
//function to detect if PHP session is started
function is_session_started()
{
if ( php_sapi_name() !== 'cli' ) {
if ( version_compare(phpversion(), '5.4.0', '>=') ) {
return session_status() === PHP_SESSION_ACTIVE ? TRUE : FALSE;
} else {
return session_id() === '' ? FALSE : TRUE;
}
}
return FALSE;
}
add_action( 'woocommerce_before_add_to_cart_button' , 'bpa_custom_add_checkout_fields', 50, 0 );
function save_recursion(){
//if the user is getting the bags with recursive dates set, we will attempt to save them so that they can be used at a later time.
if( isset($_POST['recursive_weeks']) ){
$id = 0;
if( is_user_logged_in() ){
$id = get_current_user_id();
}
// if user is not logged in or if WP couldn't get user ID
if($id > 0){
update_user_meta($id, 'bpa_meter_bag_recursion', $_POST['recursive_weeks']);
} else {
if ( is_session_started() === FALSE ) session_start();
$_SESSION['bpa_meter_bag_recursion'] = $_POST['recursive_weeks'];
}
}
}
add_action('woocommerce_add_to_cart', 'save_recursion');
function custom_add_to_cart( $item_data, $cart_item) {
//this adds the custom recursion dates to the items data
//if this is the meter bag product
if($cart_item['product_id'] == '2476'){
//check if user is logged in, get recursion from user meta. if not try to get sessions
if( is_user_logged_in() ){
$id = get_current_user_id();
$recursion = get_user_meta($id, 'bpa_meter_bag_recursion');
$_POST['recursive_weeks'];
} else {
session_start();
$recursion = $_SESSION['bpa_meter_bag_recursion'] ;
}
// change the message to reflect that this is going to be multiple dates
$item_data[0]['name'] = "First Day of First Week";
$item_data[1]['name'] = "Last Day of First Week";
//get that first week dates in the correct format
$start_date = new DateTime($item_data[0]['value']);
$end_date = new DateTime($item_data[1]['value']);
$first_start_date = $start_date->format('Y-m-d');
$first_end_date =$end_date->format('Y-m-d');
//iterate over the recursive weeks and add these as products to the cart
$week = 1;
$quantity = $cart_item['quantity'];
for($i = 1; $i <= ($recursion[0] * 2) - 2; $i++ ){
if( ($i % 2) != 0){
$item_data[$i + 1]['name'] = "First Day of the Next Week ";
$startDate = strtotime( $first_start_date . " +" . $week ." week" );
$item_data[$i + 1]['value'] = date('F jS Y', $startDate);
} else {
$item_data[$i + 1]['name'] = "Last Day of the Next Week ";
$endDate = strtotime( $first_end_date . " +" . $week ." week");
$item_data[$i + 1]['value'] = date('F jS Y', $endDate);
$week++;
}
}
if ( is_session_started() === FALSE ) session_start();
$_SESSION['recursive_dates'] = serialize($item_data);
if( isset($_SESSION['recursive_dates']) ){
//var_dump($_SESSION['recursive_dates']);
}
return $item_data;
}
}
add_filter('woocommerce_get_item_data', 'custom_add_to_cart', 10, 2);
What I am expecting to have happen is that on the product screen, the updated product total would get added to the cart total, and viewable from the cart and checkout. This works until the quantity is increased. Not sure why this is an issue since I would presume that the total would be prod_total * quantity, but that doesn't appear to be how this works. I'm not sure if this is a woo thing or an Easy Bookings thing (I'm tending to lean towards a woo thing, but my hours of research hasn't found anything, or I'm googling the wrong stuff. )
Any help in pointing me in the right direction is mucho appreciated.

Woocommerce : cart total shows zero for 1 item

I have created a link in the header of my site to the cart with the current totals.
It is supposed to show the current total of the cart and the number of items contained in the cart, in this manner :
[icon] 1.20 € - 1 article
However, the value is only correctly calculated when in the cart page. On the homepage, for example, it will only display like this :
[icon] 0.00 € - 1 article
This is how I am accessing the values :
$count = WC()->cart->cart_contents_count;
WC()->cart->calculate_totals();
if($count > 0)
{
print "<a class='cart-contents' href='" . WC()->cart->get_cart_url();
print "' title='Voir votre panier'>";
print WC()->cart->get_total();
print " - " . sprintf(_n('%d article', '%d articles', $count, 'woothemes'), $count);
print "</a>";
}
If I call WC()->cart->get_cart_total();, this will show the price exclusive of tax, even if I force prices include tax.
How can I get the correct value consistently across the site ?
global $woocommerce;
$amount = $woocommerce->cart->cart_contents_total+$woocommerce->cart->tax_total;
You can also convert $amount in float value as per your requirement.
I had the same issue so I went through the WooCommerce code. In the function WC()->cart->calculate_totals() in the class WC_Cart since some time ago there is a following condition
// Only calculate the grand total + shipping if on the cart/checkout
if ( is_checkout() || is_cart() ||
defined('WOOCOMMERCE_CHECKOUT') || defined('WOOCOMMERCE_CART') )
This condition applies to calculating specifically the total, I'm not sure why. But this gives you the proper workaround:
On the page where you need to show the total include either one of the following lines of code:
define( 'WOOCOMMERCE_CART', true );
or
define( 'WOOCOMMERCE_CHECKOUT', true );
And then perform the function WC()->cart->calculate_totals();
Then to get the cart total use either WC()->cart->total or wc_cart_totals_order_total_html() (for currency symbol)

Resources