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' );
Related
I'm trying to show stock remaining per product in a custom column on WooCommerce admin orders list, without success.
I would like to show it next to 'quantity'.
Ej. Product A x 1 (3)
My code attempt:
add_filter('manage_edit-shop_order_columns', 'new_order_items_column' );
function new_order_items_column( $order_columns ) {
$order_columns['order_products'] = "Productos";
return $order_columns;
}
add_action( 'manage_shop_order_posts_custom_column' , 'new_order_items_column_cnt' );
function new_order_items_column_cnt( $colname ) {
global $the_order; // the global order object
if( $colname == 'order_products' ) {
// get items from the order global object
$order_items = $the_order->get_items();
if ( !is_wp_error( $order_items ) ) {
foreach( $order_items as $order_item ) {
echo '▪️ ' . $order_item['name'] .' × '. $order_item['quantity'] .'<br />';
}
}
}
}
Any advice?
You can use get_stock_quantity(), note that products with variations and products that do not contain stock are also taken into account
So you get:
// Add a Header
function filter_manage_edit_shop_order_columns( $columns ) {
// Add new column
$columns['order_products'] = __( 'Products', 'woocommerce' );
return $columns;
}
add_filter( 'manage_edit-shop_order_columns', 'filter_manage_edit_shop_order_columns', 10, 1 );
// Populate the Column
function action_manage_shop_order_posts_custom_column( $column, $post_id ) {
// Compare
if ( $column == 'order_products' ) {
// Get an instance of the WC_Order object from an Order ID
$order = wc_get_order( $post_id );
// Is a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
foreach( $order->get_items() as $item ) {
// Product ID
$product_id = $item->get_variation_id() > 0 ? $item->get_variation_id() : $item->get_product_id();
// Get product
$product = wc_get_product( $product_id );
// Get stock quantity
$get_stock_quantity = $product->get_stock_quantity();
// NOT empty
if ( ! empty ( $get_stock_quantity ) ) {
$stock_output = ' (' . $get_stock_quantity . ')';
} else {
$stock_output = '';
}
// Output
echo '▪ '. $item->get_name() . ' × ' . $item->get_quantity() . $stock_output . '<br />';
}
}
}
}
add_action( 'manage_shop_order_posts_custom_column' , 'action_manage_shop_order_posts_custom_column', 10, 2 );
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 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.
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 was given code from someone on the Wordpress forum, but it isn't quite right.
It has created a column in my Product Admin called Attributes, and it is bringing in the name of the attributes, but not options. i.e. it looks like
"coloursizeyearcountry"
And I would like
"Colour = Red, Size = large, Year = 2020, Country = UK"
or something like it.
The code I have so far is:
function add_product_column( $columns ) {
//add column
$columns['new_column'] = __( 'New column', 'woocommerce' );
return $columns;
}
add_filter( 'manage_edit-product_columns', 'add_product_column', 10, 1 );
function add_product_column_content( $column, $postid ) {
if ( $column == 'new_column' ) {
// Get product object
$product = wc_get_product( $postid );
// Get Product Variations
$product_attributes = $product->get_attributes();
foreach ( $product_attributes as $product_attribute ) {
$attribute_name = $product_attribute->get_name();
echo str_replace( 'pa_', '', $attribute_name );
}
}
}
add_action( 'manage_product_posts_custom_column', 'add_product_column_content', 10, 2 );
The following code will help you get what you want. Explanation via the comment tags added in the code
function add_product_column( $columns ) {
//add column
$columns['new_column'] = __( 'New column', 'woocommerce' );
return $columns;
}
add_filter( 'manage_edit-product_columns', 'add_product_column', 10, 1 );
function add_product_column_content( $column, $postid ) {
if ( $column == 'new_column' ) {
// output variable
$output = '';
// Get product object
$product = wc_get_product( $postid );
// Get Product Variations - WC_Product_Attribute Object
$product_attributes = $product->get_attributes();
// Not empty, contains values
if ( !empty( $product_attributes ) ) {
foreach ( $product_attributes as $product_attribute ) {
// Get name
$attribute_name = str_replace( 'pa_', '', $product_attribute->get_name() );
// Concatenate
$output = $attribute_name . ' = ';
// Get options
$attribute_options = $product_attribute->get_options();
// Not empty, contains values
if ( !empty( $attribute_options ) ) {
foreach ($attribute_options as $key => $attribute_option ) {
// WP_Term Object
$term = get_term($attribute_option); // <-- your term ID
// Not empty, contains values
if ( !empty( $term ) ) {
$term_name = $term->name;
// Not empty
if ( $term_name != '' ) {
// Last loop
end($attribute_options);
if ( $key === key($attribute_options) ) {
// Concatenate
$output .= $term_name;
} else {
// Concatenate
$output .= $term_name . ', ';
}
}
}
}
}
echo $output . '<br>';
}
}
}
}
add_action( 'manage_product_posts_custom_column', 'add_product_column_content', 10, 2 );