Recently I had a project where a client needed to offer a variable product with extra information about each variation displayed, and this needed to change as the selector changed the variation. The product page would be linked to from another page on their site, with the desired variation pre-loaded in the drop-down selector on arrival. However, once there you could of course play with the drop-down to select other variations.
Let’s break down what I did to get everything working.
Here’s a quick summary:
- create a textarea that gets added to the variations editor in the Woocommerce product
- hook it in properly so it responds to javascript and normal page loading
- get the contents of the textareas and inject them into the product page on the front end
- hide all of them except the one we want to show based on the drop-down selector
The variable product custom field text area:
First, I wanted to create a textarea for each product variation for the client to be able to enter a description. Originally, I simply grabbed a plugin that did just that. But after we had a bunch of nightmares with malware and site hacking, we wiped everything and started over on a new host where we wanted to stay as clean as possible, limit our plugins, and by then that plugin had been removed from the repository. I found great instruction on adding custom fields to variable products by Remi Corson which looked easy to implement. Using his post as a guide I added a function to create the textarea and hook in properly to Woocommerce. And, as he points out, we have to deal with the Ajax creation of new variations, so everything is done twice as you’ll see. This goes in the functions file.
//Product Variation Description //Display Fields add_action( 'woocommerce_product_after_variable_attributes', 'variable_fields', 10, 3 ); //JS to add fields for new variations add_action( 'woocommerce_product_after_variable_attributes_js', 'variable_fields_js' ); //Save variation fields add_action( 'woocommerce_process_product_meta_variable', 'save_variable_fields', 10, 1 ); //Create new fields for variations function variable_fields( $loop, $variation_data, $variation ) { ?> <tr> <td> <?php // Textarea woocommerce_wp_textarea_input( array( 'id' => '_textarea['.$loop.']', 'label' => __( 'Description', 'woocommerce' ), 'placeholder' => '', 'value' => get_post_meta( $variation->ID, '_textarea', true ), ) ); ?> </td> </tr> <?php } // Create new fields for new variations function variable_fields_js() { ?> <tr> <td> <?php // Textarea woocommerce_wp_textarea_input( array( 'id' => '_textarea[ + loop + ]', 'label' => __( 'Description', 'woocommerce' ), 'placeholder' => '', 'value' => '', ) ); ?> </td> </tr> <?php } //Save new fields for variations function save_variable_fields( $post_id ) { if (isset( $_POST['variable_sku'] ) ) : $variable_sku = $_POST['variable_sku']; $variable_post_id = $_POST['variable_post_id']; // Textarea $_textarea = $_POST['_textarea']; for ( $i = 0; $i < sizeof( $variable_sku ); $i++ ) : $variation_id = (int) $variable_post_id[$i]; if ( isset( $_textarea[$i] ) ) { update_post_meta( $variation_id, '_textarea', stripslashes( $_textarea[$i] ) ); } endfor; endif; }
The code gave me this in my variable products:
Get the Description to use on the Product Page:
To get the description I had created for them and add it to the product page, I’m using the all-powerful get_post_meta, and also grabbing the price, since they are all different. I’m doing this from the functions file and hooking in to the ‘before add to cart’ in Woocommerce. As you’ll notice this is going to write them all out on the page, which is not what we want, but I added some javascript to hide them all, then turn on each one depending on what’s selected in the drop-down. This also goes in the functions file.
function my_theme_function_woocommerce_before_add_to_cart_form() { // get the product global $product; // Get the post IDs of all the product variations $variation_ids = $product->children; // check if we have variations if ( empty( $variation_ids ) ) return; // walk the variations foreach( $variation_ids as $variation_id ) { $variable_product= new WC_Product_Variation( $variation_id ); $description = get_post_meta($variation_id, '_textarea'); $price = $variable_product ->regular_price; echo '<div id="variation-' . $variation_id . '" style="display: none;" class="camp-description">'; echo '<p>'.$description[0].'</p>'; echo '<b> $'.$price.'</b>'; echo '</div>'; } } add_action( 'woocommerce_before_add_to_cart_form', 'my_theme_function_woocommerce_before_add_to_cart_form', 5 );
jQuery to show the one we want:
I needed this solution fast, so I resorted to some jQuery trickery to display the one description we want out of all the descriptions hidden on the page, based on what option was selected in the drop-down. This goes in a custom.js file that adds various extra jQuery I need on the site. It should be wrapped in the usual ‘jQuery(document).ready(function ($) {}’.
//Summer Camp products get variation ID to show/hide descriptions setTimeout(function(){ variationid= ''; if(typeof $('input[name=variation_id]').val() != "undefined" && $('input[name=variation_id]').val() !== null) { variationid = $('input[name=variation_id]').val(); $('div#variation-'+variationid).show(); } }, 100); setTimeout(function(){ $('body').on('change', '#camps',function(){ $('div#variation-'+variationid).hide(); setTimeout(function(){ variationid = $('input[name="variation_id"]').val(); $('div#variation-'+variationid).show(); }, 100) }); }, 200);
SIDE NOTE: to land on the page in the first place the user is clicking through from another page. The link they click is set up to leverage Woocommerce pre-filling the drop-down with a certain variation. The href in the link looks like this:
/summer-camp-registration/?attribute_camps=early-childhood-session-1-latin-celebrations
Wrap up:
I’m sure there are some more elegant ways to do things, but this got me what I needed in a hurry, and seems to be working fine. I’m not crazy about having the timeouts in the js to allow for all the other Woocommerce js to work, but again it’s not too much of a drag on the user experience I think. If I get time I’ll go through more explanation of how things work on here. Here is the product page where you can see this working: https://www.waldorfsandiego.org/summer-camp-registration/?attribute_camps=early-childhood-session-1-latin-celebrations
hi mick,
very interesting post, good job 🙂
anyway, currently i am using wordpress 4.3 and woocommerce 2.4
what all i need just want to get the product variation ID inside my cart items.
could you help me by showing the simple code to get the variation ID ?
thank you in advance for everything.
/*following below is my code to validate minimum order using Product ID*/
add_action( ‘woocommerce_check_cart_items’, ‘validasi_pembelian’ );
function validasi_pembelian()
{
if( is_cart() || is_checkout() )
{
global $woocommerce;
// Product Id and Min. Quantities per Product
$product_min_qty = array(
array( ‘id’ => 390, ‘min’ => 5 ),/*ipau kecil*/
array( ‘id’ => 391, ‘min’ => 3 ),/*ipau sedang*/
array( ‘id’ => 392, ‘min’ => 2 ),/*ipau besar*/ );
// Will increment
$i = 0;
// Will hold information about products that have not
// met the minimum order quantity
$bad_products = array();
// Loop through the products in the Cart
foreach( $woocommerce->cart->cart_contents as $product_in_cart ) {
// Loop through our minimum order quantities per product
foreach( $product_min_qty as $product_to_test ) {
// If we can match the product ID to the ID set on the minimum required array
if( $product_to_test[‘id’] == $product_in_cart[‘product_id’] ) {
// If the quantity required is less than than the quantity in the cart now
if( $product_in_cart[‘quantity’] < $product_to_test['min'] ) {
// Get the product ID
$bad_products[$i]['id'] = $product_in_cart['product_id'];
// Get the Product quantity already in the cart for this product
$bad_products[$i]['in_cart'] = $product_in_cart['quantity'];
// Get the minimum required for this product
$bad_products[$i]['min_req'] = $product_to_test['min'];
}
}
}
// Increment $i
$i++;
}
}
}
This code seems to be broken with the latest update to WooCommerce (2.6.1). I now have a Fatal error message and my product variations don’t show.
https://www.imagingexpressionskc.com/product/ready-made-board-collection/
Fatal error: Uncaught exception ‘Exception’ with message ‘No parent product set for variation #1’ in /home/imagingexpress/public_html/wp-content/plugins/woocommerce/includes/class-wc-product-variation.php:85 Stack trace: #0 /home/imagingexpress/public_html/wp-content/themes/ImagingExpressions/functions.php(248): WC_Product_Variation->__construct(Array) #1 [internal function]: my_theme_function_woocommerce_before_add_to_cart_form(”) #2 /home/imagingexpress/public_html/wp-includes/plugin.php(525): call_user_func_array(‘my_theme_functi…’, Array) #3 /home/imagingexpress/public_html/wp-content/plugins/woocommerce/templates/single-product/add-to-cart/variable.php(26): do_action(‘woocommerce_bef…’) #4 /home/imagingexpress/public_html/wp-content/plugins/woocommerce/includes/wc-core-functions.php(203): include(‘/home/imagingex…’) #5 /home/imagingexpress/public_html/wp-content/plugins/woocommerce/includes/wc-template-functions.php(981): wc_get_template(‘single-product/…’, Array) #6 [internal function]: woocommerce_variable in /home/imagingexpress/public_html/wp-content/plugins/woocommerce/includes/class-wc-product-variation.php on line 85
Cody- I haven’t been able to get ahead enough on work and family to dig back into this problem. As soon as I get a break I’ll see if I have any insight.
Hi , can any one help me
i have a page where i am showing my product using woocommerce product shortcode like this [product_page id=”137″],
this is a variable product with two attribute , city and date ,
after selecting city and date i want to change my all page content . how can i do this pls help
thanks in advance