I am working on a plugin that auto adjusts product prices. All of my products are variable products which has made this tougher than I can solve.
if( $product->is_type( 'variable' ) ){
foreach ( $product->get_available_variations() as $key => $variation ) {
foreach ($variation['attributes'] as $attribute ) {
if ( ! $attribute->get_weight() ) {
I have a check to make sure the product is variable. The only product Attribute is 'Size'. Here I have 4-8 different Size Variations per product. Each of these have a weight value which seemed to be default implemented by Woocommerce. I am unable to get the weight though from each variation. Curious if I am calling get_weight() from the wrong place, or if there is a different method for this.
get_weight() of course does not work so I wonder if getting attributes from variations is completely wrong?
Using WC_Variable_Product get_visible_children() (or get_children()) method, try:
global $product; // If needed | or $product = wc_get_product( $product_id );
if( $product->is_type( 'variable' ) ){
foreach ( $product->get_visible_children() as $variation_id ) {
$variation = wc_get_product( $variation_id ); // Get the product variation object
$weight = $variation->get_weight(); // Get weight from variation
if ( ! $weight ) {
echo '<div>' __("No weight") . '</div>';
} else {
echo '<div><strong>' __("Weight") . ':</strong> ' . wc_format_weight( $weight ) . '</div>';
}
}
}
or you can use WC_Variable_Product get_available_variations() as follows:
global $product; // If needed | or $product = wc_get_product( $product_id );
if( $product->is_type( 'variable' ) ){
foreach ( $product->get_available_variations() as $key => $variation_data ) {
$weight = $variation_data['weight']; // Get weight from variation
if ( ! $weight ) {
echo '<div>' __("No weight") . '</div>';
} else {
echo '<div><strong>' __("Weight") . ':</strong> ' . $variation_data['weight_html'] . '</div>';
}
}
}
Both code snippet works.
Related
I have a function to add the price to the variation name in woocommerce. But it only works correctly if the product has only one attribute. With multiple attributes it only works partially.
I am looking for a solution that also works with multiple attributes, but only one has a price (e.g. "pa_price").
And maybe it is also possible to display it only for some attribute values (e.g. pa_price has S,M,L and "other" - show the price only for S,M and L).
function display_price_in_variation_options( $term ) {
$product = wc_get_product();
$id = $product->get_id();
if ( empty( $term ) || empty( $id ) ) {
return $term;
}
if ( $product->is_type( 'variable' ) ) {
$product_variations = $product->get_available_variations();
} else {
return $term;
}
foreach ( $product_variations as $variation ) {
if ( count( $variation['attributes'] ) > 1 ) { // ...or higher value
return $term;
}
$attribute = array_values( $variation['attributes'] )[0];
if ( $attribute === $term ) {
$term .= ' (' . wp_strip_all_tags( wc_price( $variation['display_price'] ) ) . ')';
}
}
return $term;
}
add_filter( 'woocommerce_variation_option_name', 'display_price_in_variation_options' );
I have products with multiple attributes allowing for multiple dimensions of variations. I'd like to show the price difference in the dropdown, but it is not comparing the absolute minimum price, for each option.
This is the code I am using:
add_filter( 'woocommerce_variation_option_name','display_price_in_variation_option_name');
function display_price_in_variation_option_name( $term ) {
global $product;
if ( empty( $term ) ) {
return $term;
}
if ( empty( $product->id ) ) {
return $term;
}
$variation_id = $product->get_children();
$price_min = $product->get_variation_regular_price();
foreach ( $variation_id as $id ) {
$_product = new WC_Product_Variation( $id );
$variation_data = $_product->get_variation_attributes();
foreach ( $variation_data as $key => $data ) {
if ( $data == $term ) {
$html = $term;
$price_diff = $_product->get_price() - $price_min;
$price_html = '';
if ($price_diff > 0 ) { $price_html = ' (+£' . number_format((float)$price_diff, 2, '.', '') . ')';}
$html .= $price_html;
return $html;
}
}
}
return $term;
}
However, this is only showing the minimum price of the current attribute, not the product as a whole.
I hope this is clear - ideally in the above image for options that do not add cost, $price_html should be blank. The code works perfectly for variations with a single attribute option, but does not work for variations with multiple attribute options.
Your code can be simplified and optimized, but it can't work with multiple attribute dropdowns. It can only work if there is a unique attribute dropdown (see the alternative way after).
So this code works only with one attribute dropdown:
add_filter( 'woocommerce_variation_option_name','display_diff_price_in_attribute_option_name', 10, 4 );
function display_diff_price_in_attribute_option_name( $term_name, $term, $attribute, $product ) {
if ( ! is_a($product, 'WC_Product') || is_admin() ) {
return $term_name;
}
$price_min = $product->get_variation_regular_price('min', true); // Min price for display
foreach ( $product->get_children() as $variation_id ) {
$variation = wc_get_product($variation_id);
$term_value = $variation->get_attribute($attribute);
if ( $term_value == $term_name ) {
$price_diff = wc_get_price_to_display($variation) - $price_min;
if ($price_diff > 0 ) {
$term_name .= ' (+' . strip_tags( wc_price( $price_diff ) ) . ')';
}
break;
}
}
return $term_name;
}
So you need something different (when there is multiple attribute dropdowns).
The following code will display the price difference for the select variation, for example at the right of the selected variation price:
add_filter( 'woocommerce_available_variation', 'filter_available_variation_attributes', 10, 3 );
function filter_available_variation_attributes( $data, $product, $variation ){
$price_min = $product->get_variation_regular_price('min', true); // Min price for display
$price_diff = $data['display_price'] - $price_min;
if ($price_diff > 0 ) {
$data['price_html'] = '<span class="price">' . $variation->get_price_html() . ' <em>(+' . wc_price( $price_diff ) . ')</em></span>';
}
return $data;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
I have variable products with many variations where only a few items are actually In Stock while the majority of other variations are ''available on backorder''
I would like to be able to display a quick list of ONLY the items that are IN STOCK in the short product description of each product page so the customer doesn't have to try all variations one-by-one to finally find out which ones are in stock.
I've searched for plugins or code that can do this but did not find anything.
The closest code I found is:
add_action( 'woocommerce_after_shop_loop_item', 'bb_echo_stock_variations_loop' );
function bb_echo_stock_variations_loop(){
global $product;
if ( $product->get_type() == 'variable' ) {
foreach ( $product->get_available_variations() as $key ) {
$attr_string = array();
foreach ( $key['attributes'] as $attr_name => $attr_value ) {
$attr_string[] = $attr_value;
}
if ( $key['max_qty'] > 0 ) {
echo '<br/>' . implode( ', ', $attr_string ) . ': ' . $key['max_qty'] . ' in stock';
} else {
echo '<br/>' . implode(', ', $attr_string ) . ': out of stock';
}
}
}
}
But it displays "In stock" available variations on the SHOP page and I want it to be displayed on the single product short description.
How can I display "In stock" available variations in single product short description?
To display in stock variations list in product single pages on short description, use the following:
add_filter( 'woocommerce_short_description', 'display_in_stock_variations_to_short_description' );
function display_in_stock_variations_to_short_description( $excerpt ){
global $product;
if ( ! is_product() || empty($product) || ! is_a( $product, 'WC_Product' ) )
return $excerpt;
if( $product->is_type('variable') ) {
// Loop through visible children
foreach( $product->get_children() as $variation_id ) {
$variation = wc_get_product( $variation_id );
// Hide out of stock variations if 'Hide out of stock items from the catalog' is checked.
if ( ! $variation || ! $variation->exists() || ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && ! $variation->is_in_stock() ) ) {
continue;
}
// Filter 'woocommerce_hide_invisible_variations' to optionally hide invisible variations (disabled variations and variations with empty price).
if ( apply_filters( 'woocommerce_hide_invisible_variations', true, $product->get_id(), $variation ) && ! $variation->variation_is_visible() ) {
continue;
}
$max_qty = 0 < $variation->get_max_purchase_quantity() ? $variation->get_max_purchase_quantity() : $variation->get_stock_quantity();
$term_names = []; // Initializing
// Loop through variation attributes for current varation
foreach ( $variation->get_variation_attributes() as $attribute => $term_slug ) {
// Set the term name in an array
$term_names[] = ucfirst( str_replace( ['-', '_'],[' ', ' '], $term_slug ) );
}
if ( $max_qty > 0 ) {
$excerpt .= sprintf( '<br/>%s: %s %s',
implode(', ', $term_names),
$max_qty,
__('in stock', 'woocommerce')
);
}
}
}
return $excerpt;
}
// Avoid additional content from product short description to be displayed in variation description
add_filter( 'woocommerce_available_variation', 'filter_wc_available_variation_desscription', 10, 3);
function filter_wc_available_variation_desscription( $data, $product, $variation ) {
$max_qty = 0 < $variation->get_max_purchase_quantity() ? $variation->get_max_purchase_quantity() : $variation->get_stock_quantity();
if( $max_qty > 0 )
$data['variation_description'] = get_post_meta( $variation->get_id(), '_variation_description', true );
return $data;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
I am facing this issue.
Fatal error: Uncaught Error: Call to a member function is_type() on null
Will someone help me in this regard.
Here is the code I use.
add_action( 'woocommerce_before_calculate_totals', 'sione_change_cart_item_name_and_price', 10, 1 );
function sione_change_cart_item_name_and_price( $cart ) {
global $product;
// Get new items names from WC_Session
$session_data = (array) WC()->session->get( 'new_item_names' );
//$sku_data = (array) WC()->session->get( 'product_sku' );
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
if($product->is_type( 'simple' )) {
$item_names = $product->get_short_description();
} else {
$item_names = $cart_item['data']->get_name() .", ". $cart_item['data']->get_attribute('color'). "," . $cart_item['data']->get_attribute('gender') . " (Product SKU: " . $cart_item['data']->get_sku() . ")";
}
// If item name doesn't exist in WC_Session for this cart item, we do it
if( ! isset($session_data[$cart_item_key]) ) {
$session_data[$cart_item_key] = $item_names;
WC()->session->set( 'new_item_names', $session_data );
}
}
}
Any help will be appreciated. Thanks
You can determine the product type in the following way
function sione_change_cart_item_name_and_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get an instance of the WC_Product object
$product = $cart_item['data'];
// Get product id
$product_id = $cart_item['product_id'];
if( $product->is_type( 'simple' )) {
echo 'Simple = ' . $product_id . '<br>';
} else {
echo 'Else = ' . $product_id . '<br>';
}
}
}
add_action( 'woocommerce_before_calculate_totals', 'sione_change_cart_item_name_and_price', 10, 1 );
Following Loic's workflow here Can I get all the variations related to the product basing on one particular variation in default value.
Example: Get all variations with attribute_pa_sizes similar to the default value's attribute_pa_sizes
echo $variation_values['attributes']['attribute_pa_sizes'] . ': ' . $price ;
This can be done with the following code (based on this answer):
<?php
global $product;
$variation_ids = array();
$targeted_attribute = 'pa_sizes';
if( $product->is_type('variable') ){
$default_attributes = $product->get_default_attributes();
foreach($product->get_available_variations() as $variation_values ){
foreach($variation_values['attributes'] as $key => $attribute_value ){
$attribute_name = str_replace( 'attribute_', '', $key );
if( $attribute_name == $targeted_attribute ){
$default_value = $product->get_variation_default_attribute($attribute_name);
if( $default_value == $attribute_value ){
// We set all related variation IDs in an array
$variation_ids[] = $variation_values['variation_id'];
}
}
}
}
if( count( $variation_ids ) > 0 ){
// Iterating through each variation ID
foreach( $variation_ids as $variation_id ){
// Get the "default" WC_Product_Variation object
$variation = wc_get_product($variation_id);
// Get variation attribute values
$variation_attributte = $variation->get_variation_attributes();
// Raw output variation attribute values
echo '<pre>'; print_r($variation_attributte); echo '</pre>';
// Get the active price
$price = $variation->get_price();
// Output price
echo '<p>Price: ' . $price . '</p>';
}
}
}
?>
Tested and works