I’ve been working on a large Woocommerce site recently. Woocommerce gets updated regularly and unfortunately the documentation doesn’t always cover the new features.
Generally when I come across a new problem I ask Google. It’s easier to adapt code than it is to write it from scratch. To be honest, I find the attribute system a little confusing. I came across this Stack Overflow article, which helped. Then I realised there was a much easier way.
Step 1 – Create a Woocommerce action
Edit functions.php in your child theme. Add the following:
//show attributes after summary in product single view add_action('woocommerce_single_product_summary', function() { //template for this is in storefront-child/woocommerce/single-product/product-attributes.php global $product; echo $product->list_attributes(); }, 25);
Reload the page for a product. You should now see the table of attributes.
Step 2 – Customise the output (optional)
The design I was working with showed the attributes in columns, not rows. I wanted the attribute name above each value. The Woocommerce template uses a table, which means I needed to edit the output.
If you haven’t already, create the directories woocommerce/single-product in your child theme. Copy the file product-attributes.php from the templates/single-product directory in the Woocommerce plugin. You can now edit this file to control the output.
Here’s the code that I used:
<?php /** * Product attributes * * Used by list_attributes() in the products class. */ // Instead of showing the attributes in a left-right table, // we show them as columns with the name above each value. if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly } $has_row = false; $attributes = $product->get_attributes(); ob_start(); ?> <div class="product_attributes"> <?php foreach ( $attributes as $attribute ) : if ( empty( $attribute['is_visible'] ) || ( $attribute['is_taxonomy'] && ! taxonomy_exists( $attribute['name'] ) ) ) continue; $values = wc_get_product_terms( $product->get_id(), $attribute['name'], array( 'fields' => 'names' ) ); $att_val = apply_filters( 'woocommerce_attribute', wpautop( wptexturize( implode( ', ', $values ) ) ), $attribute, $values ); if( empty( $att_val ) ) continue; $has_row = true; ?> <div class="col"> <div class="att_label"><?php echo wc_attribute_label( $attribute['name'] ); ?></div> <div class="att_value"><?php echo $att_val; ?></div><!-- .att_value --> </div><!-- .col --> <?php endforeach; ?> </div><!-- .product_attributes --> <?php if ( $has_row ) { echo ob_get_clean(); } else { ob_end_clean(); }
If you compare this to the original you can see I’ve removed the code for displaying weight and dimensions and made some other simplifications.
That’s it – now you’re good to go!
Did this post help you out, or just confuse you? Let me know in the comments!
Comments 32
Great post!
Is there a way to modify the display order of the attribute labels (att_label)? I have Googled it thoroughly but I can only find methods to sort the attribute values (att_value) when there are multiple values.
I’m not sure – try creating an intermediate array that contains all your att_labels and att_values. Sort that array by att_label, and then once it’s sorted, loop through it again to display it.
Thanks so much. Your article teaches me how to modify functions.php for the first time!!! I am a newbie.
Great post!
How do I not display the empty attributes?
Tks
I am not good with CSS. Can you help me display a bulleted list like this?
* Lot No.: MG01-008
* Size: 20x30in
* Subject: Medieval, Nature, Scenic
* Year of Creation: 1979
* Medium: Oil on Canvas
* Medium Description: Mounted Canvas Used
* Available Types: Original
* Framing: Framed, Removable
* Status: Available
Also, what will be the full path for the file as per step 2?
Hi Mohit
...
. Then inside the foreach loop, replaceTo answer your other comment, the full paths would be something like /path/to/site/wp-content/plugins/woocommerce/templates/single-product/product-attributes.php which gets copied to /path/to/site/wp-content/themes/your-theme/woocommerce/single-product/product-attributes.php
It did give me a bulleted list but, one small change needed:
Current:
* Lot No.
TEST-1101
Wanted:
* Lot No. : TEST-1101
Hi Friend, will you be able to help me?
David Nash,
Great post no doubts this is for single product page but I want to display same information or attributes on the product page can you help me for that. Hopes you will.
Thanks in advance!!
Rahul,
Thank you for your post. I have got the same question like Mohit
one small change needed:
Current:
* Lot No.
TEST-1101
Wanted:
* Lot No. : TEST-1101
Thank you ))
You need to replace –
$att_val = apply_filters( ‘woocommerce_attribute’, wpautop( wptexturize( implode( ‘, ‘, $values ) ) ), $attribute, $values );
TO: $att_val = apply_filters( ‘woocommerce_attribute’, implode( ‘, ‘, $values ), $attribute, $values );
Thank you so much David – This was very helpful. I tried using the Woocommerce Show Attribute Plugin but it would only show one attribute even when I had made all the attributes visible on the product page.
Your code is wonderful as it solved my problem 🙂
Thank you for this code man! Cheers to you!
I know it’s maybe a bit late for this,
But with 3.1.0 upgrade o WooCommerce,
$product->id has been deprecated. Official announcement on GitHub says to use
$product->get_id()
I have personally tested in on WP 4.8 and WC 3.1.1. Works great and doesn’t give an error “Product attributes should not be accessed directly[…]”.
Hope this helps someone.
Thanks Maciej, I appreciate you taking the time to let me know! This post still gets a lot of views and I’ve updated it with your suggestion.
Hello…I would like to place an object after attributes and before quantity selector /add to the cart button…Is there an after-attributes hook ? or Is there a hook for the before qty/add to the cart Button ?
Not sure about that one. I find WooCommerce hooks a little frustrating, there seems to be plenty of them where you don’t need them, and none where you do!
I would find the relevant file in woocommerce/templates/ and copy that to your theme directory, and then modify that – you could add the “global $product; echo $product->list_attributes();” lines where you want it.
I’m not sure which file would be the right one off the top of my head, but my general process to find it is do a text search on all files in the directory (using grep or similar) to find strings you see in the developer console.
Hi
David
Its Very Helpful but
But “”attr_val”” value has long string size which is to print in New line
E.g.
Color:
Black
Instead of
Color:Black
I have tried trim function also but still it showing me in different line
Plzz Help me For this I am stuk since 2 days
Thank you
Hi Sandeep – That sounds like a CSS issue – try setting “display: inline” on the elements.
THANK YOU! THANK YOU! THANK YOU! Was scratching my head trying to figure out this one!
Hi David,
It is so clear no confusion, straight to the target.
How can I use this code to add attributes to a pdf packing slip template?
Thank you David, could not get this to work until your article showed up in Google 🙂
Thanks Koen, glad it was helpful!
Thank you. A lot of frustrated hours later and fixed in seconds after reading this post.
Thanks Bridget, it’s always good to get positive feedback!
Hi there!
Thanks for this post, I have a question though: How could I modify it for the attributes to be shown on single product page, cart&checkout table and emails? So basically through the whole order process?
I have tried plugins for this but they don’t work the way I want to.
Thanks for any help,
Nil
Thank you for this code man!
thank you .
Great, worked for me. Only I want to control where the attributes are shown.; instead of below the product price. Let’s say I have three rows on the product page.
1. Left row shows a product image
2. Middle row shows the product information
3. Right row should show the product attributes.
How can I make it show in the right row. E.g. via a short code.
Best, Chris
can I show product attributes using a shortcode?