I was recently tasked with setting the County (billing_state / shipping_state) fields in the WooCommerce checkout to be required fields.
The standard way to override these billing and shipping fields is to use the woocommerce_billing_fields and woocommerce_shipping_fields filters, like this:
add_filter( 'woocommerce_billing_fields', 'mp_filter_state_billing', 5, 1 ); add_filter( 'woocommerce_shipping_fields', 'mp_filter_state_shipping', 5, 1 ); function mp_filter_state_billing( $address_fields ) { $address_fields['billing_state']['required'] = true; $address_fields['billing_state']['label'] = 'Blah'; return $address_fields; } function mp_filter_state_shipping( $address_fields ) { $address_fields['shipping_state']['required'] = true; $address_fields['shipping_state']['label'] = 'Blah'; return $address_fields; }
However, although that does set the fields as required, the fields are immediately over-written by address-i18n.js which sets them back to the locale defaults i.e. state is optional.
The documentation states that you should use the woocommerce_default_address_fields filter instead, for example:
add_filter( 'woocommerce_default_address_fields', 'mp_require_state_field' ); function mp_require_state_field( $fields ) { $fields['billing_state']['required'] = true; $fields['shipping_state']['required'] = true; return $fields; }
But this had no effect in my tests.
I found lots of attempts to solve this problem online, with some even trying to use jQuery to remove the optional status of the field and make it required by writing in the right classes. Ugggh!
Surely we need to change the default settings for the locale (GB)? After all, this is where the address-i18n.js is getting the values from. In woocommerce/includes/class-wc-countries.php, there is a function:
public function get_country_locale() { if ( empty( $this->locale ) ) { $this->locale = apply_filters( 'woocommerce_get_country_locale', array( 'AE' => array( 'postcode' => array( 'required' => false, 'hidden' => true, ), 'state' => array( 'required' => false, ), ),
..including the part where the UK default settings are set:
'GB' => array( 'postcode' => array( 'label' => __( 'Postcode', 'woocommerce' ), ), 'state' => array( 'label' => __( 'County', 'woocommerce' ), 'required' => false, ), ),
So we can use the woocommerce_get_country_locale filter to modify the locale settings array:
add_filter( 'woocommerce_get_country_locale', 'mp_change_locale_field_defaults'); function mp_change_locale_field_defaults($countries) { $countries['GB']['state']['required'] = true; return $countries; }
Voila! It sets both the billing_state and shipping_state field to required, and retains its correct status when you change countries.
The standard way to override these billing and shipping fields is to use the woocommerce_billing_fields and woocommerce_shipping_fields filters
Solved it! Thanks Robin
Thank you, Robin! Now all I needto do is add this filter… I’ve spent a lot of time lookingfor this solution, so I’m overjoyed! Appreciate yourassistance.
Thank you. This does not appear to be documented anywhere. Apart from a comment on one bug saying “need to filter the country locale”…
How do i make this easier to find on google?
Hi Robin
Sorry I’m not the most technical so would appreciate some guidance 🙂 I also need to change the county (not country) option to be REQUIRED instead of OPTIONAL.
Can anyone guide me please. This is my page… https://wintonbrewery.com/shop/checkout.
Ta
Pete
Thanks for this solution to a very confusing problem, it provided a sort of workaround for a bug however,
If i switch to another country the county* label shows but there is no text box. This prevents checkout progression.
i am based in and have tested uk and i tested germany and france. works as expected with Uk and not with the other two.
Hey Robin, If I want to remove extra fields from checkout page then how can I do this? as I am already working on it going through this tutorial but getting unknown errors. Can you help me to resolve this error?
function remove_additional_information_checkout($fields){
unset( $fields[“billing_last_name”] );
unset( $fields[“billing_middle_name”] );
return $fields;
}
add_filter( ‘woocommerce_billing_fields’, ‘remove_additional_information_checkout’ );
Here is the tutorial https://www.cloudways.com/blog/how-to-edit-delete-fields-and-email-in-woocommerce-custom-checkout-fields/ that I am following to implement the code
Thank you so much for this! most appreciate you sharing the knowledge.
Superb! Been pondering this one for a long time. Thank you
Thanks!
You’re a genius! Thank you so much. Up till now I’ve been doing it manually. But of course it runs the risk of being lost every time there’s an update. Now I can just add this filter and leave it as is. Wasted so many hours looking for this solution so I’m thrilled! Cheers.
Glad you found it useful.