How to Add Custom Fields to Product Variations
Long time ago I published a tutorial where I described how to add custom fields to WooCommerce products. Now it is time to dive deep into product variations and add a couple settings fields there as well.
Also recommend you my plugin Simple Variation Swatches, because it is really simple!
Where Exactly We Can Display a Variation Custom Field?
The same way, as with the products themselves it is possible to place a field in a different location related to the other variation fields. Let’s figure out what options do we have here.
woocommerce_variation_options_pricing
Let’s begin with the first hook that displays custom fields (or anything you want) at the very beginning of variation settings block, just after the prices.
Let’s try it this way:
add_action( 'woocommerce_variation_options_pricing', 'rudr_v_fields', 10, 3 );
function rudr_v_fields( $loop, $variation_data, $variation ) {
echo '<p class="form-row form-row-full">hey there</p>';
}
There are you can also see 3 arguments available inside the function:
$loop
– it is just an iteration count of a variation we are currently editing. If it is the first one in the list, it will be0
, the second one –1
and 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]
.$variation
–WP_Post
object of this specific variation. For example it allows to get a variation ID easily with$variation->ID
.
Do not know where to insert the code by the way?
And here we are:

woocommerce_variation_options_inventory
This hook is going to display your field in “Inventory” field group which is shown only if Manage stock? checkbox is checked.
add_action( 'woocommerce_variation_options_inventory', 'rudr_v_fields' );
function rudr_v_fields( $loop ) {
echo '<p class="form-row form-row-full">hey there</p>';
}

woocommerce_variation_options_dimensions
This hook will going to display your field just under “Weight” and “Dimensions” fields which are displayed only if Virtual checkbox is unchecked.
woocommerce_variation_options_download
This hook will going to display your field just under “Download limit” and “Download expiry” fields which are displayed only if Downloadable checkbox is checked.
woocommerce_product_after_variable_attributes
This hook will display your fields at the very end of all variation settings, under the “Description” field.
Add a Custom Field
Creating a field for variation settings is quite simple, the only thing to keep in mind is that you do not have to use regular HTML like <input type="text"/>
, but instead – special WooCommerce functions. For a 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, $variation ) {
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( $variation->ID, 'rudr_text_field', true )
)
);
}
There are a couple moments to highlight in the code above:
- I recommend to add class
form-row
to the wrapper, otherwise the field is not going to have the same styles as the rest of the fields. You can also useform-row-first
andform-row-last
when 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.

Field Types
Above we have added just a simple text field using woocommerce_wp_text_input()
function, but of course the other field types are also can be added here. But we need to use an according function for every 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.
But checkboxes and radio buttons look like they aren’t supported as variation settings, I mean they will be displayed of course and will work also, but the styling needs some customization, you will see it on 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, $variation ) {
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( $variation->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( $variation->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( $variation->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( $variation->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( $variation->ID, 'rudr_check', true ),
)
);
woocommerce_wp_hidden_input(
array(
'id' => 'hidden_field[' . $loop . ']',
'value' => 'hey there'
)
);
}
Result:

Save Custom Field Values as a Variation Metadata
In order to save fields into post meta we are going to use a hook, which is woocommerce_save_product_variation
and a function update_post_meta()
.
Also always remember about sanitizing 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 ] );
}
Showing the fields conditionally
You remember, a little bit above in this tutorial, when I show 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 displaying for the specific fields only. All we need to do is to add a specific CSS class to wrapper_class
parameter.
For example if you add:
woocommerce_wp_checkbox(
array(
'id' => 'my_check[' . $loop . ']',
'label' => 'Checkbox field',
'wrapper_class' => 'form-row show_if_variation_virtual',
...
Then this checkbox 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 post meta, we can get the field values anytime and almost anywhere using 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 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 10 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!!