Skip to content

Instantly share code, notes, and snippets.

@simonlk
Last active February 21, 2022 20:27
Show Gist options
  • Save simonlk/3967956 to your computer and use it in GitHub Desktop.
Save simonlk/3967956 to your computer and use it in GitHub Desktop.
Output Woocommerce product variations as a table within a tab on the single product page
// Add to functions.php
/*===================================================
Created by sk from Renegade Empire with help
from these sources:
http://docs.woothemes.com/document/editing-product-data-tabs/
http://www.sean-barton.co.uk/2013/03/remove-woocommerce-20-reviews-tab/#.UYnWe7XfB6N
http://www.sean-barton.co.uk/2013/03/sb-add-woocommerce-tabs-wordpress-plugin/#.UYrYL7XfB6M
====================================================*/
/*===================================================
Options
====================================================*/
$re_wcvt_options = array(
'tab_title' => 'Product Variations', // change the tile of the tab
'sku_title' => 'REF #', // change the sku column heading
'show_price' => 'yes', // show price column: yes or no
'show_description' => 'yes', // show description column: yes or no
'tab_priority' => '5', // 5 is good to make the tab appear first
);
/*===================================================
Add the tab
====================================================*/
add_filter( 'woocommerce_product_tabs', 're_woo_product_variations_tab' );
function re_woo_product_variations_tab() {
global $woocommerce, $product, $post, $re_wcvt_options;
// $available_variations = $product->get_available_variations();
// $attributes = $product->get_attributes();
if (is_product() and $product->product_type == 'variable') {
// Adds the new tab
$tabs['variations_table'] = array(
'title' => __( $re_wcvt_options['tab_title'], 'woocommerce' ),
'priority' => 50,
'callback' => 're_woo_product_variations_tab_content'
);
return $tabs;
}
}
/*===================================================
Build the tab content
====================================================*/
function re_woo_product_variations_tab_content() {
global $woocommerce, $product, $post, $re_wcvt_options;
$available_variations = $product->get_available_variations();
$attributes = $product->get_attributes();
// The new tab content
//echo '<h2>Product Variations</h2>';
//echo '<p>Here\'s your new product tab.</p>';
?>
<table class="table table-striped table-hover table-bordered varations-table tablesorter">
<thead>
<tr>
<th><?php echo $re_wcvt_options['sku_title']; ?></th>
<?php
// Show description if option is set to yes
if ($re_wcvt_options['show_description'] == 'yes') : ?>
<th>Description</th>
<?php endif; ?>
<?php foreach ( $attributes as $name => $options) :?>
<th>
<?php
//echo $woocommerce->attribute_label($name);
$attr_name = $options['name'];
if (0 === strpos($attr_name, 'pa_')){
$attr_name = $woocommerce->attribute_label($attr_name);
}
echo $attr_name;
?>
</th>
<?php endforeach;?>
<?php
// Show price if option is set to yes
if ($re_wcvt_options['show_price'] == 'yes') : ?>
<th>Price</th>
<?php endif; ?>
<th class="var-qty">&nbsp;</th>
<th class="var-add-to-cart">&nbsp;</th>
</tr>
</thead>
<tbody>
<?php
/*
echo '<pre>';
print_r($re_wcvt_options);
echo '</pre>';
*/
?>
<?php foreach ($available_variations as $prod_variation) : ?>
<?php
// get some vars to work with
$post_id = $prod_variation['variation_id'];
$post_object = get_post($post_id);
//echo '<pre>';
//print_r($prod_variation);
//echo '</pre>';
?>
<tr>
<td>
<?php
// echo substr($prod_variation['sku'], 5, 100) ; // output SKU but trim the first part that is added
echo $prod_variation['sku'];
?>
</td>
<?php
// Show description if option is set to yes
if ($re_wcvt_options['show_description'] == 'yes') : ?>
<td>
<?php
$variation_desc = get_post_meta( $post_object->ID, '_description', true);
if ( !empty($post_object->post_content)){
$variation_desc = $post_object->post_content; // post content
} elseif (!empty($variation_desc)) {
$variation_desc = get_post_meta( $post_object->ID, '_description', true); // get meta description
} else {
$variation_desc = get_the_title($product->id); // parent title
}
echo $variation_desc;
?>
</td>
<?php endif; ?>
<?php foreach ($prod_variation['attributes'] as $attr_name => $attr_value) : ?>
<td>
<?php
// Get the correct variation values
if (strpos($attr_name, '_pa_')){ // variation is a pre-definted attribute
$attr_name = substr($attr_name, 10);
$attr = get_term_by('slug', $attr_value, $attr_name);
$attr_value = $attr->name;
} else { // variation is a custom attribute
//$attr = maybe_unserialize( get_post_meta( $post->ID, '_product_attributes' ) );
//$attr_value = var_dump($attr);
//$attr = get_term_by('slug', $attr_value, $attr_name);
//$attr_value = $attr->name;
}
echo $attr_value;
?>
</td>
<?php endforeach;?>
<?php
// Show price if option is set to yes
if ($re_wcvt_options['show_price'] == 'yes') : ?>
<td><?php echo get_woocommerce_currency_symbol() . get_post_meta( $post_object->ID, '_price', true); ?></td>
<?php endif; ?>
<form action="<?php echo do_shortcode('[add_to_cart_url id="'.$product->id.'"]'); ?>" class="variations_form cart" method="post" enctype="multipart/form-data" data-product_id="<?php echo $product->id; ?>">
<td>
<?php woocommerce_quantity_input(); ?>
</td>
<td>
<input type="hidden" name="variation_id" value="<?php echo $post_id; ?>">
<?php foreach ($prod_variation['attributes'] as $attr_name => $attr_value) : ?>
<input type="hidden" name="<?php echo sanitize_title($attr_name); ?>" value="<?php echo $attr_value ;?>">
<?php endforeach;?>
<button type="submit" class="btn btn-small button add-to" type="button">Add to cart</button>
</td>
</form>
</tr>
<?php endforeach;?>
</tbody>
</table>
<?php
//echo '<pre>';
//print_r($prod_variation['attributes']);
//echo '</pre>';
?>
<?php
}
/*===================================================
Tab Position
====================================================*/
add_filter( 'woocommerce_product_tabs', 're_woo_move_variation_table_tab', 98);
function re_woo_move_variation_table_tab($tabs) {
global $re_wcvt_options;
if ($tabs['variations_table']) {
$tabs['variations_table']['priority'] = $re_wcvt_options['tab_priority'];
}
return $tabs;
}
@helgatheviking
Copy link

heads up there is a stray closing </div> on line 123. very neat code, btw.

@simonlk
Copy link
Author

simonlk commented May 14, 2013

Thanks for the feedback and comments everyone! It's getting to the point where I'm working it into a plugin now so I can add features that can be switched on/off from backend.

Nice one @Rajbir4all i'll have to add that as an option when this turns into a plugin!

@hiphones it works fine with any number of attributes from my tests. You have to make sure that on each of your variations have a value selected for each attribute.

Thanks @helgatheviking and I've removed the stray!

@simonlk
Copy link
Author

simonlk commented May 15, 2013

Added some basic options now you can just edit the options part of the code to change.

@hiphones
Copy link

hiphones commented Jun 5, 2013

suppose it want "empty price" to show as "call for price" any code i need to add on sir. thank you for your generosity

@blesid
Copy link

blesid commented Jun 13, 2013

Hi,

I've added this to my functions file, but it removes the other tabs that would be shown instead of adding it alongside the description and additional information tabs.

I'm using mystile as a theme, and have the option to display attribute tabs selected.

Is this supposed to replace or add an additional tab?

Cheers

@exotica1123
Copy link

Hi,
You have done good work.II' ve also used it on my website.But the issue is it removes other tabs which are required for product details.
Any solutions? Actually I am searching for the solution which let a single add to cart button for all selected variations and quantity.

@hiphones
Copy link

hiphones commented Jul 1, 2013

sorry i try all the ways to make all the variations not misplace i have 4 attributes here http://www.hi-phones.com/?product=ipad-mini

@iuzdn
Copy link

iuzdn commented Jul 18, 2013

Hi there,
Nice code!
Although I've got the same problem it replaces existing tabs. Is there any solution to it?
Many thanks in advance.
PS: How to make it show qty in stock?

@iuzdn
Copy link

iuzdn commented Jul 18, 2013

Hey, I figured it out.. you create the new tab but it overrides the existing ones. The solution is to pass the $tabs variable (that contains all existing tabs) through the function, and then append the variables of the current tab to it.
I did it this way:
declare function like this 're_woo_product_variations_tab($tabs)'
then add an 'else { return $tabs; }' /for non-variable products/ in the end of the function.
That's it! now it works perfectly.

@ejntaylor
Copy link

This is looking promising, thanks for adding. I think a few of us are looking for the functionality that you can get when you have grouped products but by using variations. This would display each variation with it's own quantity and then a single add to cart button. More here: http://wordpress.stackexchange.com/questions/82949/woocommerce-multiple-input-field-for-multiple-product-variations

@Rajbir4all
Copy link

Hello,

Is it possible that same product variations table can display above the Tabs, actually i don't wanna display it in tabs, just wanna show directly above the tabs .

Please suggest ?

Thanks

@aabellowins
Copy link

Fantastic! Very handy stuff!

@mbilalsiddique1
Copy link

The new created tab is working fine but there is no data in other tabs

@blesid
Copy link

blesid commented Feb 18, 2014

Hi, This was working well until the new version of Woocommerce. The items will now no longer add to cart as the information sent to the cart regarding variables is now in a new format. I think it needs to send 3 hidden variables - "add-to-cart", "product_id" and "variation_id". Currently it is sending "variation_id" and "attribute_pa_format".

Also the tab is created, but it removes all other tabs. Any ideas?

@emilysnothere
Copy link

Just wondering if there is an update for this since the latest Woocommerce update? The add to cart button no longer works

@emilysnothere
Copy link

This worked for me replace line 169 to 181 above with the following:


<form class="variations_form cart" method="post" enctype='multipart/form-data' data-product_id="<?php echo $product->id; ?>" data-product_variations="<?php echo esc_attr( json_encode( $available_variations ) ) ?>">

    <td>
    <?php woocommerce_quantity_input(); ?>
    </td>
    <td>

    <input type="hidden" name="add-to-cart" value="<?php echo $product->id; ?>" />
    <input type="hidden" name="product_id" value="<?php echo $product->id; ?>" />
    <input type="hidden" name="variation_id" value="<?php echo $post_id; ?>" />
    <div class="variations_button">
        <?php foreach ($prod_variation['attributes'] as $attr_name => $attr_value) : ?>
            <input type="hidden" name="<?php echo sanitize_title($attr_name); ?>" value="<?php echo $attr_value ;?>">
            <?php endforeach;?>
        <button type="submit" class="btn btn-small button add-to"><?php echo $product->single_add_to_cart_text(); ?></button>
    </div>  
    </td>
</form>

@tagplus5
Copy link

emilysnothere, thanks, now it works. Woocommerce 2.1.6

@mediavinc
Copy link

Hi,
Thanks a lot for this code. I've just install it on a fresh Woocommerce 2.1.12 (and WP 3.9.2) and it does the job!
However, I am facing a problem regarding the attributes display order...

I have created three predefined attributes (with custom ordering) and I have created a variable product with some variations.
When I display the product page, I have the table headings <th> that are in the correct order but the data below in the table row <td> are not matching...
In fact, when I am in the product edit page, on the attributes tab, I drag and drop the attributs to set the order and save the product. When I reload the product page on frontend, the heading have changed but not the columns below.

Does anyone have a fix?

Here are the two loops in my function.php:

<?php foreach ($attributes as $name => $options) :?>
  <th>
                        <?php 
                            $attr_name = $options['name'];
                            if (0 === strpos($attr_name, 'pa_')){
                                $attr_name = $woocommerce->attribute_label($attr_name);
                            }
                            echo $attr_name;
                        ?>
  </th>
<?php endforeach;?>

and

<?php foreach ($prod_variation['attributes'] as $attr_name => $attr_value) : ?>
  <td>
                        <?php
                            if (strpos($attr_name, '_pa_')){ // variation is a pre-definted attribute
                                $attr_name = substr($attr_name, 10);
                                $attr = get_term_by('slug', $attr_value, $attr_name);
                                $attr_value = $attr->name;
                            } 

                            else { // variation is a custom attribute
                                //$attr = maybe_unserialize( get_post_meta( $post->ID, '_product_attributes' ) );
                                //$attr_value = var_dump($attr);
                                //$attr = get_term_by('slug', $attr_value, $attr_name);
                                //$attr_value = $attr->name;
                            }
                            echo str_replace(array('-','_'), ' ', $attr_value);

                        ?>
  </td>
<?php endforeach;?>

@actua
Copy link

actua commented Sep 12, 2014

Could it be obtain the variations in a dropdown?
For example:

<select .... >
    <option ...> Red Color + Size XL: (12,00 €)  
    ...
    ...
</select>

@onestopdive
Copy link

how to show the stock level of each product ?

@davemoz
Copy link

davemoz commented Nov 22, 2014

I'm trying to display a plain-text list of product attributes (either names or IDs), such as colors, underneath each product on the archive/catalog page. Which part of this code would I use to do this? I know it's in there, but all I need is the attributes plain-text output. Anyone know?

Copy link

ghost commented Jan 5, 2015

Hi i'm currently having a problem to display value of the attributes..

At the moment it's working nicely except that the variation values output the sanitized version i.e. '3.4 x 2.3' outputs as '34-23'

echo str_replace(array('-','_'), ' ', $attr_value) <-- i did use this but it's not really perfect since there are some '.' not showing up as in 'slug' of the term

Anyone have found the work arround for it? -thx in advance-

@RonR-WebDesign
Copy link

Has anyone figured out how to do only one "Add to Cart" button? Fill in the quantities and press one button would be awesome!

@alison18
Copy link

This is a great feature & has been working for me until I Updated Wordpress & Woocommerce.

I think this is the error I am getting


Fatal error: Call to undefined function add_filter() in [...][...] on line 34

If someone could help me I would really appreciate it! Thanks

@Namennaj
Copy link

Hi @renegadesk. Please look at line 178 of your code. Your Button have two types in there. That may be causing your issue.

@ignacioazzi
Copy link

Has anyone been able to make this work with the "Add to Cart" button using an Ajax Call? Everytime I hit the "Add to Cart" button the page refresh and it changes to the Description Tab.

@mattbee
Copy link

mattbee commented Mar 18, 2016

The error "Call to undefined method WooCommerce::attribute_label()..." can be fixed by updating the name of the method on lines 83 and 86, to $woocommerce->**wc_**attribute_label($name)

@Winsiders
Copy link

Winsiders commented Sep 29, 2017

you need to add $tabs in this function, if not, only the tab in the function will be display :
function re_woo_product_variations_tab( $tabs ) {
And $woocommerce is depreciate in WC 3+ - use WC()

@plumdm
Copy link

plumdm commented Feb 9, 2018

This is great, thanks! Not sure if you ended up doing it, but you should definitely package this into a plugin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment