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.

WooCommerce StoreFront Theme Checkout Page
The checkout page on my test website. Storefront theme is active.

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!

print checkout fields with woocommerce_checkout_fields filter hook
You can see an array with all the fields available. And our goal is to modify this array inside the hook!

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.

WooCommerce Default Fields Validation.
Sometimes clients ask me to turn this validation off.

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.

You can easily remove unnecessary checkout fields in WooCommerce.
If you receive payments on your website, especially payments by card, please, be careful with removing fields.

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!

Ordering checkout fields in WooCommerce, unexpected result.

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:

On this screenshot we have changed the label of the First name field and the placeholder of the Order Notes field.

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 nameDescription
woocommerce_before_checkout_billing_formBefore all billing fields
woocommerce_after_checkout_billing_formAfter all billing fields
woocommerce_before_checkout_registration_formBefore customer registration form
woocommerce_after_checkout_registration_formAfter customer registration form
woocommerce_before_checkout_shipping_formBefore all shipping fields
woocommerce_after_checkout_shipping_formAfter all shipping fields
woocommerce_before_order_notesAt the very beginning of “Additional information” section.
woocommerce_after_order_notesAt 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:

Add custom checkout fields WooCommerce
After inserting the above code to your 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.

Custom meta fields in WooCommerce orders
If you can not find this metabox on the edit order page, turn it on in Screen Option tab which you can find on the top right part of the screen.

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.

Example of the WooCommerce error notice when custom required checkout fields are empty or not valid.
Misha Rudrastyh

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

Follow me on Twitter