07967 325669 info@mootpoint.org

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.