WooCommerce Product Variations Add-to-Cart Grid / Table

Due to a lot of suggestions and feedback, I have reworked these snippets into a Variations Grid plugin


woocommerce-price-grid

Recently, I had a client request that their Woocommerce products appear in a ‘grid’ style format, instead of the default dropdowns. Here is my solution – but please keep in mind if you have many variations, this grid-style format probably doesn’t look to hot, so use it is you see fit. I have included a special meta so you can turn this feature off for any product you don’t want to appear in this style.

Toggle Variations grid-style layout on/off

To turn this grid-style layout, simply add a new meta with the name price_grid, and give it any value, false works best.

How I created the Woocommerce product grid

For those of you who are curious how it’s done, or who may want to make your own updates, I began by overriding the call to woocommerce_variable_add_to_cart, which attempts to load the template responsible for showing the default Variable Product add to cart area – the one with the dropdowns.

I then use the function find_valid_variations to loop through all the variations and flesh them out – because Woocommerce only saves the explicit variations, all your variants with an ‘any’ attribute aren’t actually created, for this to work we need to fill in the blanks so to speak, and this function does that. It then returns the full array of possible variations for your product – and this should technically work for any number of attributes, but I’ve only tested with two. If you’re keen let me know how it works for 3+ attributes.

We then take this fully fleshed out variations array and simply loop through and create a simple form for each variation, including a quantity field! The order of the attributes is determined by their order on the attributes tab, see the example below – flavour would come first, with the size last.

woocommerce-price-grid-ordre

And the final result:

woocommerce-price-grid-fullexample

And here they are added to a cart:

woocommerce-price-grid-cart

WooCommerce Product Variations Add-to-Cart Grid / Table:

Copy the following two functions into your functions.php (or wherever)

woocommerce_variable_add_to_cart overrides the default template, and substitutes our grid!

function woocommerce_variable_add_to_cart(){
    global $product, $post;

    $variations = find_valid_variations();

    // Check if the special 'price_grid' meta is set, if it is, load the default template:
    if ( get_post_meta($post->ID, 'price_grid', true) ) {
        // Enqueue variation scripts
        wp_enqueue_script( 'wc-add-to-cart-variation' );

        // Load the template
        wc_get_template( 'single-product/add-to-cart/variable.php', array(
                'available_variations'  => $product->get_available_variations(),
                'attributes'            => $product->get_variation_attributes(),
                'selected_attributes'   => $product->get_variation_default_attributes()
            ) );
        return;
    }

    // Cool, lets do our own template!
    ?>
    <table class="variations variations-grid" cellspacing="0">
        <tbody>
            <?php
            foreach ($variations as $key => $value) {
                if( !$value['variation_is_visible'] ) continue;
            ?>
            <tr>
                <td>
                    <?php foreach($value['attributes'] as $key => $val ) {
                        $val = str_replace(array('-','_'), ' ', $val);
                        printf( '<span class="attr attr-%s">%s</span>', $key, ucwords($val) );
                    } ?>
                </td>
                <td>
                    <?php echo $value['price_html'];?>
                </td>
                <td>
                    <?php if( $value['is_in_stock'] ) { ?>
                    <form class="cart" action="<?php echo esc_url( $product->add_to_cart_url() ); ?>" method="post" enctype='multipart/form-data'>
                        <?php woocommerce_quantity_input(); ?>
                        <?php
                        if(!empty($value['attributes'])){
                            foreach ($value['attributes'] as $attr_key => $attr_value) {
                            ?>
                            <input type="hidden" name="<?php echo $attr_key?>" value="<?php echo $attr_value?>">
                            <?php
                            }
                        }
                        ?>
                        <button type="submit" class="single_add_to_cart_button btn btn-primary"><span class="glyphicon glyphicon-tag"></span> Add to cart</button>
                        <input type="hidden" name="variation_id" value="<?php echo $value['variation_id']?>" />
                        <input type="hidden" name="product_id" value="<?php echo esc_attr( $post->ID ); ?>" />
                        <input type="hidden" name="add-to-cart" value="<?php echo esc_attr( $post->ID ); ?>" />
                    </form>
                    <?php } else { ?>
                        <p class="stock out-of-stock"><?php _e( 'This product is currently out of stock and unavailable.', 'woocommerce' ); ?></p>
                    <?php } ?>
                </td>
            </tr>
            <?php } ?>
        </tbody>
    </table>
    <?php
}

find_valid_variations loops through your product variations and fills in the ‘anys’

function find_valid_variations() {
    global $product;

    $variations = $product->get_available_variations();
    $attributes = $product->get_attributes();
    $new_variants = array();

    // Loop through all variations
    foreach( $variations as $variation ) {

        // Peruse the attributes.

        // 1. If both are explicitly set, this is a valid variation
        // 2. If one is not set, that means any, and we must 'create' the rest.

        $valid = true; // so far
        foreach( $attributes as $slug => $args ) {
            if( array_key_exists("attribute_$slug", $variation['attributes']) && !empty($variation['attributes']["attribute_$slug"]) ) {
                // Exists

            } else {
                // Not exists, create
                $valid = false; // it contains 'anys'
                // loop through all options for the 'ANY' attribute, and add each
                foreach( explode( '|', $attributes[$slug]['value']) as $attribute ) {
                    $attribute = trim( $attribute );
                    $new_variant = $variation;
                    $new_variant['attributes']["attribute_$slug"] = $attribute;
                    $new_variants[] = $new_variant;
                }

            }
        }

        // This contains ALL set attributes, and is itself a 'valid' variation.
        if( $valid )
            $new_variants[] = $variation;

    }

    return $new_variants;
}