How to Add Custom Fields to Variations in WooCommerce
Some time ago, I published a tutorial about adding custom fields to products. I covered variable products there; however, I didn’t cover adding custom fields specifically to variations of variable WooCommerce products.
Now, I decided that it is time to dive deep into custom fields for variations as well, at least because recently I’ve been adding one to my Inventory Sync for WooCommerce plugin:

In this tutorial, we’ll learn how to work with WooCommerce’s custom fields for variations. Since the new WooCommerce product editor is still in development, I’ll show you examples of how to do it only for the classic product editor, which is widely in use, by the way.
Hooks in Variation Settings (Where Exactly to Add a Custom Field)
A handful of hooks are available in WooCommerce, which allow us to decide where exactly in variation settings we would like to display our custom field.
Let’s take a quick look and decide which hook we’re going to use.
woocommerce_variation_options_pricing
Let’s begin with the first hook, which displays custom fields (or anything you want) at the very beginning of the variation settings block, just after the prices.
Here is a simple code snippet to begin with:
add_action( 'woocommerce_variation_options_pricing', function( $loop, $variation_data, $post ) {
echo '<p class="form-row form-row-full">hey there</p>';
}, 25, 3 );Let’s take a look at the arguments of the function:
$loop– it is just an iteration count of a variation we are currently editing. If it is the first one, it will be0, the second one –1and so on.$variation_data– an array with all variation fields settings the same way as they are stored in post meta. For example$variation_data[ '_regular_price' ][0].$post–WP_Postobject of this specific variation. For example, it allows us to get a variation ID easily with$post->ID.
I hope you know where to insert this code, by the way.
And here we are:

woocommerce_variation_options_inventory
With the help of this hook, you can easily display your variation custom field in the “Inventory” field group, which is, by the way, shown only if the “Manage stock?” checkbox is checked.
add_action( 'woocommerce_variation_options_inventory', function( $loop ) {
echo '<p class="form-row form-row-full">hey there</p>';
} );
woocommerce_variation_options_dimensions
This hook will display your field just under the “Weight” and “Dimensions” fields, which are displayed only if the “Virtual” checkbox is unchecked.
woocommerce_variation_options_download
This hook will display your field right under the “Download limit” and “Download expiry” fields, which are visible only if the “Downloadable” checkbox is checked.
woocommerce_product_after_variable_attributes
This hook will display your variation custom fields at the very end of all variation settings under the “Description” field.
Example of Adding a Custom Field to Variations
Now, let’s jump straight to an example. Right now, I am going to show you two ways that you can use in WooCommerce to add a custom field to product variations – programmatically and with the help of a plugin, and I am going to use my Simple Fields plugin for that.
Add a custom field to a variation in WooCommerce using a plugin
Let’s start with the plugin approach. Its main advantage is not only that your code snippet is going to be much smaller and simpler, but also that it allows you to add some interesting fields like “Image“, “Gallery“, “Post relationship“, etc.
For example, let’s add this bunch of custom fields:

All you need to do is use the code snippet below.
add_filter( 'simple_register_product_variation_fields', function( $option_groups ) {
$option_groups[] = array(
'fields' => array(
array(
'id' => 'text_test',
'label' => 'Text',
'description' => 'Some field description text',
),
array(
'id' => 'select_test',
'label' => 'Select',
'type' => 'select',
'placeholder' => 'Choose from options...',
'options' => array(
'val1' => 'Option 1',
'val2' => 'Option 2',
),
),
array(
'id' => 'gallery_test',
'label' => 'Gallery',
'type' => 'gallery'
),
array(
'id' => 'select2_test',
'label' => 'Tags',
'type' => 'select',
'placeholder' => 'Select tags…',
'multiple' => true,
'options' => array(
'val1' => 'Option 1',
'val2' => 'Option 2',
'val3' => 'Option 3',
'val4' => 'Option 4',
),
),
array(
'id' => 'post_test',
'label' => 'Related post',
'type' => 'post',
'post_type' => 'post',
),
),
);
return $option_groups;
}If you don’t know where to insert it, please read this guide.
Add a custom field to a product variation programmatically
If you decide to use a programmatic approach rather than a plugin, then you are going to face some challenges, not that significant, though:
- You can only use “Text”, “Textarea”, and “Select” fields; all the other types of fields will require additional coding from you.
- You will need an extra step – saving field data into the database and handling proper sanitization.
In any case, I will explain the exact step-by-step process to you below.
Let’s start with the moment that you do not have to use regular HTML like <input type="text"/>, but instead – special WooCommerce functions. For example, for a simple text field, it would be woocommerce_wp_text_input().
add_action( 'woocommerce_product_after_variable_attributes', 'rudr_field', 10, 3 );
function rudr_field( $loop, $variation_data, $post ) {
woocommerce_wp_text_input(
array(
'id' => 'text_field[' . $loop . ']',
'label' => 'Text field value',
'wrapper_class' => 'form-row',
'placeholder' => 'Type here...',
'desc_tip' => true,
'description' => 'We can add some description for a field.',
'value' => get_post_meta( $post->ID, 'rudr_text_field', true )
)
);
}There are a couple of moments to highlight in the code above:
- I recommend adding the class
form-rowto the wrapper; otherwise, the field is not going to have the same styles as the rest of the fields. You can also useform-row-firstandform-row-lastwhen displaying the fields in two columns. - The description of the field is going to be displayed when you hover on a question mark in case
'desc_tip' => true, and is going to be displayed under the field otherwise.

Above, we have added just a simple text field using woocommerce_wp_text_input() function, but of course, the other field types can also be added here. But we need to use a proper function for each field type.
woocommerce_wp_textarea_input()– for textarea fields,woocommerce_wp_select()– for select fields,woocommerce_wp_radio()– for radio fields,woocommerce_wp_checkbox()– for checkbox fields,woocommerce_wp_hidden_input()– for hidden fields.
However, the checkboxes and radio buttons look weird, like they aren’t supported in variation settings. I mean, they will be displayed, of course, and will also work, but the styling needs some customization from your side; you will see exactly what I mean in the screenshot below.
All the functions have almost the same arguments, but of course, there are some differences as well. In order to make it clear, let’s take a look at the example.
add_action( 'woocommerce_product_after_variable_attributes', 'rudr_fields', 10, 3 );
function rudr_fields( $loop, $variation_data, $post ) {
woocommerce_wp_text_input(
array(
'id' => 'text_field[' . $loop . ']',
'label' => 'Text field value',
'wrapper_class' => 'form-row',
'placeholder' => 'Type here...',
'desc_tip' => 'true',
'description' => 'We can add some description for a field.',
'value' => get_post_meta( $post->ID, 'rudr_text', true )
)
);
// Textarea
woocommerce_wp_textarea_input(
array(
'id' => 'textarea_field[' . $loop . ']',
'label' => 'Textarea field',
'wrapper_class' => 'form-row',
'value' => get_post_meta( $post->ID, 'rudr_textarea', true ),
)
);
// Select
woocommerce_wp_select(
array(
'id' => 'select_field[' . $loop . ']',
'label' => 'Select field',
'wrapper_class' => 'form-row',
'description' => 'We can add some description for a field.',
'value' => get_post_meta( $post->ID, 'rudr_select', true ),
'options' => array(
'one' => 'Option 1',
'two' => 'Option 2',
'three' => 'Option 3'
)
)
);
woocommerce_wp_radio(
array(
'id' => 'radio_field[' . $loop . ']',
'label' => 'Radio field',
'wrapper_class' => 'form-row',
'value' => get_post_meta( $post->ID, 'rudr_radio', true ),
'options' => array(
'one' => 'Option 1',
'two' => 'Option 2',
'three' => 'Option 3'
)
)
);
woocommerce_wp_checkbox(
array(
'id' => 'my_check[' . $loop . ']',
'label' => 'Checkbox field',
'wrapper_class' => 'form-row',
'value' => get_post_meta( $post->ID, 'rudr_check', true ),
)
);
woocommerce_wp_hidden_input(
array(
'id' => 'hidden_field[' . $loop . ']',
'value' => 'hey there'
)
);
}Result:

To save custom field values into the database, we need to use another WooCommerce hook, which is woocommerce_save_product_variation.
Plus, always remember to sanitize field values and use appropriate functions for that.
add_action( 'woocommerce_save_product_variation', 'rudr_save_fields', 10, 2 );
function rudr_save_fields( $variation_id, $loop ) {
// Text Field
$text_field = ! empty( $_POST[ 'text_field' ][ $loop ] ) ? $_POST[ 'text_field' ][ $loop ] : '';
update_post_meta( $variation_id, 'rudr_text', sanitize_text_field( $text_field ) );
// Textarea Field
$textarea_field = ! empty( $_POST[ 'textarea_field' ][ $loop ] ) ? $_POST[ 'textarea_field' ][ $loop ] : '';
update_post_meta( $variation_id, 'rudr_textarea', sanitize_textarea_field( $textarea_field ) );
// Select Field
$select_field = ! empty( $_POST[ 'select_field' ][ $loop ] ) ? $_POST[ 'select_field' ][ $loop ] : '';
update_post_meta( $variation_id, 'rudr_select', sanitize_text_field( $select_field ) );
// Radio Field
$radio_field = ! empty( $_POST[ 'radio_field' ][ $loop ] ) ? $_POST[ 'radio_field' ][ $loop ] : '';
update_post_meta( $variation_id, 'rudr_radio', sanitize_text_field( $radio_field ) );
// Checkbox field
$checkbox_field = ! empty( $_POST[ 'my_check' ][ $loop ] ) ? 'yes' : 'no';
update_post_meta( $variation_id, 'rudr_check', $checkbox_field );
// Hidden
update_post_meta( $variation_id, '_hidden', $_POST[ 'hidden_field' ][ $loop ] );
}By the way, using the update_post_meta() function is fine for saving custom fields for variations; however, I would recommend switching to a more efficient approach by using the WC_Product_Variation object and its method update_meta_data(). I use this approach in my Simple Fields plugin, of course.
Showing the fields conditionally
Do you remember, a little bit above in this tutorial, when I showed you the action hooks, I said that some of the hooks will display the fields only if a specific checkbox, “Virtual”, “Manage Stock?”, etc., is checked or unchecked?
We can configure this conditional display for the specific fields only. All we need to do is add a specific CSS class to wrapper_class parameter.
For example, if you add:
array(
'id' => 'text_test',
'label' => 'Text',
'wrapper_class' => 'show_if_variation_virtual',
...Or, for the programmatic approach:
woocommerce_wp_text_input(
array(
'id' => 'text_field[' . $loop . ']',
'label' => 'Text field value',
'wrapper_class' => 'form-row show_if_variation_virtual',
...Then this field is going to be displayed for Virtual products only! There are a couple more of them:
show_if_variation_virtual,hide_if_variation_virtual– show or hide the field for virtual products only.show_if_variation_downloadable,hide_if_variation_downloadable– show or hide for downloadable products only.show_if_variation_manage_stock,hide_if_variation_manage_stock.
Displaying Field Values on the Frontend
Because we store the variation data in the post meta, we can get the field values anytime and almost anywhere using the get_post_meta() function. Just like that:
$text_field = get_post_meta( $variation_id, 'rudr_text', true );As an example, let’s display the field value here:

In order to do that, we have to do two things. The first one is to add our custom field in the woocommerce_available_variation hook.
add_filter( 'woocommerce_available_variation', function( $variation ) {
$variation[ 'text_field_anything' ] = get_post_meta( $variation[ 'variation_id' ], 'rudr_text', true );
return $variation;
} );Then we have to alter a WooCommerce template variation.php from templates/single-product/add-to-cart of a plugin to woocommerce/single-product/add-to-cart of your theme. And then add a line with the field in the duplicated file:
...
<div class="woocommerce-variation-availability">{{{ data.variation.availability_html }}}</div>
<div class="woocommerce-variation-textfdsf">{{{ data.variation.text_field_anything }}}</div>
...
Misha Rudrastyh
Hey guys and welcome to my website. For more than 15 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me
Thank you very much for the valuable perfect code!!
Hi Misha,
Very helpfull!!
I have a question. If value is empty, how can I hide the line?
I follow your example, so I have this:
Example field: {{{ data.variation.text_1 }}}
If the field text_1 is not empty, I show the DIV and the value.
If the field text_1 is empty, how I hide the DIV?
I try this but nopn working:
{{{ #if data.variation.text_1 }}}
Example field: {{{ data.variation.text_1 }}}
{{{ else }}}
{{{/if }}}
Thank you!!