Checkout Fields Tutorial
This is all in one tutorial about WooCommerce checkout fields. We are going to edit WooCommerce checkout page by removing fields, renaming them, making them optional or required and of course, we are going to add a custom field to checkout as well.
Well, let’s get started. But first of all, let me introduce you woocommerce_checkout_fields
filter hook. Most of the things we are going to do with its help.
woocommerce_checkout_fields
If you are here just because you want to remove some unnecessary checkout fields or because you would like to disable ZIP code validation, you can safely skip this step. But if you want to understand the whole process, you’re in the right place.
Ok, so, first of all open your WooCommerce shop checkout. For me it looks like this.

Just in case, if you’re interested in how to change “Place order” button text, here is how.
So our first goal is to figure out how woocommerce_checkout_fields
filter hook works. In order to do that, please open functions.php
of your current theme (please use on a test website) and paste there this code snippet:
add_filter( 'woocommerce_checkout_fields' , 'misha_print_all_fields' );
function misha_print_all_fields( $fields ) {
//if( !current_user_can( 'manage_options' ) )
// return; // in case your website is live
echo '<pre>';
print_r( $fields ); // wrap results in pre html tag to make it clearer
exit;
}
And… now you can refresh the checkout page in your browser!

After inserting this piece of code you will see the array of all checkout fields with the parameters instead of the checkout form. As you can see in array, these fields are sorted by groups: billing
, shipping
, account
, order
.
Disable Zip Post Code, Phone Number and State Validation
There is a super-detailed tutorial about checkout fields validation on my blog as well.
Below is the validation.

Yes, in this post we will work mostly with woocommerce_checkout_fields
, but sometimes, when you have both billing and shipping fields in your checkout it is better to use woocommerce_default_address_fields
action hook (which is described in a separate tutorial) because it affects both shipping and billing fields at the same moment.
So, it will be easier to disable post code and state validation with it.
add_filter( 'woocommerce_default_address_fields', 'misha_disable_address_fields_validation' );
function misha_disable_address_fields_validation( $address_fields_array ) {
unset( $address_fields_array[ 'state' ][ 'validate' ] );
unset( $address_fields_array[ 'postcode' ][ 'validate' ] );
// you can also hook first_name and last_name, company, country, city, address_1 and address_2
return $address_fields_array;
}
Well, but what is with the phone field? It is not included in the address fields array. We will use woocommerce_checkout_fields
to disable its validation.
add_filter( 'woocommerce_checkout_fields', 'misha_no_phone_validation' );
function misha_no_phone_validation( $checkout_fields ) {
unset( $checkout_fields[ 'billing' ][ 'billing_phone' ][ 'validate' ] );
return $checkout_fields;
}
Remove Checkout Fields
One day my client asked me to remove all the checkout fields except name, email and phone, because she wanted her customers to pay by cash when they come to her office to receive purchased products.
I think it is obvious, but please, do not hide checkout fields with CSS.
Removing fields is one of the most easiest steps in this tutorial. And here is how to do it:
add_filter( 'woocommerce_checkout_fields', 'misha_remove_fields', 9999 );
function misha_remove_fields( $checkout_fields ) {
// she wanted me to leave these fields in checkout
// unset( $checkout_fields[ 'billing' ][ 'billing_first_name' ] );
// unset( $checkout_fields[ 'billing' ][ 'billing_last_name' ] );
// unset( $checkout_fields[ 'billing' ][ 'billing_phone' ] );
// unset( $checkout_fields[ 'billing' ][ 'billing_email' ] );
// unset( $checkout_fields[ 'order' ][ 'order_comments' ] ); // remove order notes
// and to remove the billing fields below
unset( $checkout_fields[ 'billing' ][ 'billing_company' ] ); // remove company field
unset( $checkout_fields[ 'billing' ][ 'billing_country' ] );
unset( $checkout_fields[ 'billing' ][ 'billing_address_1' ] );
unset( $checkout_fields[ 'billing' ][ 'billing_address_2' ] );
unset( $checkout_fields[ 'billing' ][ 'billing_city' ] );
unset( $checkout_fields[ 'billing' ][ 'billing_state' ] ); // remove state field
unset( $checkout_fields[ 'billing' ][ 'billing_postcode' ] ); // remove zip code field
return $checkout_fields;
}
I set 9999
priority to the hook because I want to run it as late as possible. Of course if you remove the checkout billing details, you shouldn’t hope that card payments will work for you. Of course they won’t. But if you would like to use PayPal Standard, everything should be ok.
After implementing the above code my checkout looks like this.

If you want to disable terms and conditions checkbox, you actually do not need any code, just go to WooCommerce settings and turn it off there. Read here where to find it.
Make Checkout Fields Optional or Required
Well, let’s continue with the same story – my client asked me: “Misha, please make the phone and email fields fullwidth, place email before phone and let’s make last name and phone fields not required”.
I begin with making fields not required. All you need is to change the only parameter in the fields array, let’s do it now:
add_filter( 'woocommerce_checkout_fields' , 'misha_not_required_fields', 9999 );
function misha_not_required_fields( $fields ) {
unset( $fields[ 'billing' ][ 'billing_last_name' ][ 'required' ] ); // that's it
unset( $fields[ 'billing' ][ 'billing_phone' ][ 'required' ] );
// the same way you can make any field required, example:
// $fields[ 'billing' ][ 'billing_company' ][ 'required' ] = true;
return $fields;
}
Change Fields Order
If you read this post from the beginning, you remember that client asked me to place the email field before the phone.
I decided it would be better to create an additional tutorial about fields reordering.
Right now I am not going to talk about it in details but I will provide a ready code for you.
add_filter( 'woocommerce_checkout_fields', 'misha_email_first' );
function misha_email_first( $checkout_fields ) {
$checkout_fields[ 'billing' ][ 'billing_email' ][ 'priority' ] = 99;
return $checkout_fields;
}
Each field within a group has a priority value, and our phone field has 100
priority, but a email field – 110
priority. So to change these fields order we just have to set the email field priority to the value less than 100
.
Works!

Change Labels and Placeholders
Below you can find the code that allows to change the label of the billing first name field and the placeholder of the order notes field.
add_filter( 'woocommerce_checkout_fields' , 'misha_labels_placeholders', 9999 );
function misha_labels_placeholders( $f ) {
// first name can be changed with woocommerce_default_address_fields as well
$f[ 'billing' ][ 'billing_first_name' ][ 'label' ] = 'Your mom calls you';
$f[ 'order' ][ 'order_comments' ][ 'placeholder' ] = 'What\'s on your mind?';
return $f;
}
And the result:

Add Your Own Custom Checkout Fields
In this part of the post I will add two fields to the WooCommerce checkout form — a dropdown select just under the billing details and “Subscribe” checkbox to the order notes section. The first field will be a required field.
I will also try to describe this process in details.
If you’re going to add some customer address fields, better check this tutorial.
Checkout hooks
First of all we should decide where we would like to place our new fields. And we have plenty of choices.
Hook name | Description |
---|---|
woocommerce_before_checkout_billing_form | Before all billing fields |
woocommerce_after_checkout_billing_form | After all billing fields |
woocommerce_before_checkout_registration_form | Before customer registration form |
woocommerce_after_checkout_registration_form | After customer registration form |
woocommerce_before_checkout_shipping_form | Before all shipping fields |
woocommerce_after_checkout_shipping_form | After all shipping fields |
woocommerce_before_order_notes | At the very beginning of “Additional information” section. |
woocommerce_after_order_notes | At the very end of “Additional information” section. |
These hooks may not work for you just in one case — if WooCommerce default checkout templates: form-shipping.php
and form-billing.php
were overridden in the theme. In that case you can manually add the new fields to your theme files, /woocommerce/checkout
directory.
Add Fields
// add fields
add_action( 'woocommerce_after_checkout_billing_form', 'misha_select_field' );
add_action( 'woocommerce_after_order_notes', 'misha_subscribe_checkbox' );
// save fields to order meta
add_action( 'woocommerce_checkout_update_order_meta', 'misha_save_what_we_added' );
// select
function misha_select_field( $checkout ){
// you can also add some custom HTML here
woocommerce_form_field(
'contactmethod',
array(
'type' => 'select', // text, textarea, select, radio, checkbox, password, about custom validation a little later
'required' => true, // actually this parameter just adds "*" to the field
'class' => array( 'misha-field', 'form-row-wide' ), // array only, read more about classes and styling in the previous step
'label' => 'Preferred contact method',
'label_class' => 'misha-label', // sometimes you need to customize labels, both string and arrays are supported
'options' => array( // options for or
'' => 'Please select', // empty values means that field is not selected
'By phone' => 'By phone', // 'value'=>'Name'
'By email' => 'By email'
)
),
$checkout->get_value( 'contactmethod' )
);
// you can also add some custom HTML here
}
// checkbox
function misha_subscribe_checkbox( $checkout ) {
woocommerce_form_field(
'subscribed',
array(
'type' => 'checkbox',
'class' => array( 'misha-field form-row-wide' ),
'label' => ' Subscribe to our newsletter.',
),
$checkout->get_value( 'subscribed' )
);
}
// save field values
function misha_save_what_we_added( $order_id ){
if( ! empty( $_POST[ 'contactmethod' ] ) ) {
update_post_meta( $order_id, 'contactmethod', wc_clean( $_POST[ 'contactmethod' ] ) );
}
if( ! empty( $_POST[ 'subscribed' ] ) && 1 === $_POST[ 'subscribed' ] ) {
update_post_meta( $order_id, 'subscribed', 1 );
}
}
The result:

functions.php
or to your custom plugin, the new fields will appear on the checkout page.And after submitting the order you will see that the checkout field values appeared in the new order Custom Fields metabox.

What about adding the field values into Order Details metabox, to customer Order Details page and to emails.
Make fields required
But what to do with the new checkout fields validation? required
parameter of the woocommerce_form_field() just adds a *
symbol near the field label, but do not process the validation.
This small piece of code prints the notice if the preferred contact method has not been not selected. As I said before, for a custom checkout field it is not enough just to set required
parameter to true
to make it really required.
add_action( 'woocommerce_checkout_process', 'misha_check_if_selected' );
function misha_check_if_selected() {
// you can add any custom validations here
if ( empty( $_POST[ 'contactmethod' ] ) ) {
wc_add_notice( 'Please select your preferred contact method.', 'error' );
}
}
Look at the second parameter of the wp_add_notice()
function — it also supports success
and notice
notice types, but error
is the only one that is relevant here.


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
Hi,
Is there anyway to add a custom field after shipping?
What i want to do is to place a select field hidden at first…but when a customer chooses a shipping method, the select field will be visible so the customer can select from the list…
Hi,
You can get currently selected by a customer shipping method using
WC()->session->get( 'chosen_shipping_methods' )[0];
.Thanks going in-depth with this. Any idea how to make the billing state field not required when a checkbox is checked?
Hi,
I think it is better to make the field not required using the hooks mentioned above. After that you can make it required or not required in jQuery.
P.S. when insert the code, use please the buttons in editor, otherwise your code or/and comments will be removed 🙃
Thanks I got this working.
P.S. Would be nice if your comment system allowed edits 🙃
I have a question! I would like to amend the “I have read and accept the terms and conditions” to “I am 18 and have read and accept the terms and conditions”. How do I do this? What code do I need to add and where do I add it?
Hi,
I’m not sure if there is a way just to change that text. You can do it of course using
gettext
filter but I do not think it is a good idea.So, the best way is to add your own checkbox, read this chapter.
Thanks by the post.
Hi Misha,
Thanks for article it pointed me in the right direction – my client wanted to only have the phone number as a required field if the country was outside of the UK which I’ve implemented with the code below…. however, how what is the best way of adjusting the required field css depending on which country is chosen?
Hi Andrew,
I think you can add classes the same way:
Hi Misha,
Sorry I don’t think I explained what I meant very well there. The code in my previous comment does work to change required fields (tested by clicking proceed to payment without filling any details in) but as the form is already loaded it doesn’t update the css so the red ‘*’ to indicate it is a required field does change after selection. I think I’ll have to delve into the javascript to sort that but I’m not quite sure how best to do that – I think it’s a similar issue to that reported here – https://github.com/woocommerce/woocommerce/issues/12409 (the problem is I haven’t got very much javascript experience and the woo stuff seems a bit ‘in at the deep end’). Will have a play around though and see if I can get something working.
Ok, I see.
I recommend you to begin with checking if any classes were changes during form submitting.
Hi Misha,
Someone on the woocommerce support WP forum was kind enough to provide the solution so just in case it’s useful to anyone the full code was
Hi Andrew,
Thank you very much for sharing!
hello misha , I want to sell the products to only a few cities , I want to change state and city fields to drop down list , please help , thank you
Hey,
I think you can safely remove that fields and then add your own but with the same NAME attributes.
please give me the codes
I do not have this code.
thanks
Hi I made the code and it worked successfuly I whould like to share it with you and your visitors … also there is a plugin may help the article be more useful …
also when shipping is on you need this :
Thank you for sharing the code.
you’re welcome …
I am looking for code or plugin to shipping by city can you help??
How can I allow checkout when shipping methods not selected ?
Go WooCommerce > Settings > General, then Disable Shipping.
This was awesomely helpful.
Thanks to you.. :D
thank you , nice article .
very helpful! thank you
This was really helpful, thanks!
Also, I have a question, how do I check if someone filled in a standard field (for example billing_address_1)?
Hey Joren,
You can inspect the default checkout fields names in your browser console. So, for billing address it will be something like this:
if( !empty( $_POST['billing_address_1'] ) ) {
This tutorial was really helpful.
Please tell how to prepopulate the new custom field..
can i use echo
$current_user->contactmethod
where should i insert this code in my plugin to see the change is has effected?
Try the
functions.php
file of your current theme.how to modify shipping states in woocommerce. In need billing states same as default but want to display shipping state limited at my own choice.
how to set shipping fields
when i push button “Next” i need to check all inputs (first name, last name) and dont make next step when any inputs == “”
what i need to do? can you help me please?
This article is very helpfull.
Also i have a question to ask you, Before Billing Section I want to register user with custom fields. I tried with woocommerce_before_checkout_billing_form hook, but it comes under the billing details. How can i do this?
Add class to Fileds was very helpful :) TNX
Does “Custom error notice” only work with own created fields?
I tried to change the error messages for “Billing_first_name” but it doesen’t really work.
It adds my custom message, but also showing the old/standard message too.
Is there a snippet for changing the error messages for standard fields? (first name, last name, city, etc.)
Hi Stefan,
Sure, you can do it with the help of
woocommerce_checkout_required_field_notice
filter hook, example:Wow!
You really are a code guru.
Thanks Misha!
I’m glad to help 🙃
Hi Misha,
is it possible to add a custom field after billing_company field?
For example a field for VAT
thanks
Hi Carlos,
I think the best option for you is
woocommerce_after_checkout_billing_form
. As I know there is no way to place a new field between the specific fields in groups like “billing fields”.But you can always do a trick – rename one of the default fields by the way.
Hi Misha,
yes, finally I used this option: woocommerce_after_checkout_billing_form and I have tried to change the order (to put billing_company in last position) , but I don’t know why I need to remove billing_country field for the order to work… do you know what is the reason?
thanks
Sorry, I do not understand what is happening in your code now 🙃
Hi Misha
Thanks for your article! I wonder if it’s possible to force a “refresh” when a select field changes. I’ve converted the billing_state field to an array that renders as a select, it works great, however if the user selects another state it does not recalculate the shipping costs.
Do you know any method to force the recalculation from the same PHP function? I’ve tried this code but it does not work :(
Thanks in advance for your time and help.
Hi David,
Try this:
You rock!
🙃
Hello Misha,
Many thanks for your article. It has been very helpful!
One question though … Is there any way to add a ‘invalid’ class to a field when the input was incorrect? Right now I’m only able to display an error message but the field doesn’t get marked red.
In my case the billing first name has to have at least 2 characters. The code I have so far:
Any help would be much appreciated!
Hello Matthieu,
You have to do it with JS/jQuery, I suppose.
Your PHP code looks good but there is no way to add the field class with it.
Hello Misha,
Many thanks for your quick response. I’ll give it a try.
Hi Misha,
Thank you very much for the great tutorial! Really helped a lot.
Could you please let me know if there would be a posssibility to have conditionals incorporated into this code?
My current code looks a lot like the contact method you have, only I use it for timeslots and ask the time of preference. So naturally I would like to check the current time (this works) and only show the timeslots that are after the current time, so you can’t make an appointment for today on a time that has already passed. ie make an appointment for 11 am when it’s already 3pm in the afternoon.
Hey Maria,
If I understand you correctly, your code could look like:
Something like this 🙃
Works perfectly! Thank you so much Misha!
Hi Misha,
Woocommerce checkout page shows individual error if the required fields are empty. Normally, if all fields are empty, all errors for those empty fields will be shown.
Billing first name is a required field
Billing last name is a required field
Billing street address is a required field
Biiling town / city is a required field
and so on…
Is it possible to show only one error if all the required fields are empty? Like “ERROR: All fields are empty. Please fill in all required fields to place order.” Can you help me how to achieve this?
Hey Maynard,
You’re lucky – you asked this question in right time and in a right place 🎉
I’ve just published a tutorial about that a couple minutes ago, here it is.
Good heavens. Thank you Misha. I’ll give it a try.
Hi Misha,
Can you further explain why you’ve set the priority when removing the fields to 9999? i couldn’t understand your explanation…
Hi Roee,
At this specific case there is no reason to set
9999
. But when you’re trying to remove a field and nothing happens, you definitely have to increase the priority parameter.Great article,
One thing though – The order page doesn’t contain the custom fields option (neither in the screen settings options). You can display the fields though in the Order details section on the order page with the following code:
Thank you! 🙃
There is also a tutorial about that.
Great article Misha!
You would want to note in the article that the Shipping Section can be entirely disabled by navigating to:-
Woocommerce->Settings->Shipping->Shipping Options->Shipping destination
and selecting option “Force shipping to the customer billing address”.
Thanks for the note ;)
Bro thanks so much your tutorials are great!
You’re welcome! I’m glad to help!
Hi Misha,
Thanks for your article. I have an issue where if the customer is purchasing a gift card (which is virtual) the woocommerce final checkout page changes the comment in brackets next to the postcode field from the red asterik to “(optional)” but when they try to pay and complete the transaction, the error message will appear asking for postcode field to be completed. So the remark of “optional” is not true. How can I replace the “optional” remark with a red asterisk? Thanks
Hi Sydney,
I think we are talking about billing postcode field? The billing postcode field is required by default, so I think it is kind of JS code of your theme which does it.
Do you have a chance to check if the same happens with WooCommerce default (Storefront) theme?
This is the best tutorial I found on the subject. Very clear and thorough. Thank you for sharing Misha.
you are awesome!!
you solved almost every question I had, thank you!!!
Hi Misha,
I am trying to change the labels of billing_address_1 (and shipping_address_1) to something like Street + streetnumber, since my customers seem to forget the street number sometimes. I used the following snippet in my functions.php as described on this page, but it does not seem to work:
The billing_address_1 field still shows as Street so it does not seem to work. Let me know if you have an idea how to fix it. I am sure a few other readers might benefit from it, too.
Thanks,
Tim
Hey Tim,
Thank you for a great question!
It seems like it works but WooCommerce change it back with JavaScript. For now I recommend you to use
woocommerce_default_address_fields
filter hook. Example:This code will work out automatically for both billing and shipping address fields.
Great article as always!
I’d like to ask you if you know how to use select2 in the checkout fields… I read something about selectWoo that allows you to use select2 without creating conflicts … but I don’t know where to start :O
Temporarily I solved this way …
Hi Misha,
Thanks a lot for this post.
I need to add a filter for first and last name fields. After checkout, I want to make all the name in the constant way: first letter in Uppercase with strtolower and ucfirst PHP function.
Have you an idea?
Thanks
Hi Msha,
Wonderfull article!
Please, do you know where I can remove or hide the Subtotal column in the checkout page?
Thanks a lot
Hi Misha! great tutorial, thanks for sharing
I do have a question. I’m trying to populate the options of a select input with values from an array
Im trying this:
but i’m getting all keys and values as a single line label as the first and only option of the select dropdown.
Hey John,
'options' => $time_range
, you were close :)Hi, thank you for your help and your work here.
I need a help :(
Need to add “endpoint filter to redirect to payment processor”
and could not find a solution.
Great tutorial, Thanks
I want to remove the country field because i sell to only one country
but when i remove this field it give me error :
“Please enter an address to continue”
it only works when i disable the shipping from the Woocommerce setting
but i cant disable shipping because i sell physical products
In that case you could try to create a hidden country field. Or even just hide it with CSS.