Make Woocommerce Checkout Phone Field Optional Based on Shipping Country

Make Woocommerce checkout phone field optional based on shipping country

The following code will make billing phone field required only for specific "Shipping" countries.

Since Woocommerce version 3.4+, things have changed a bit on Woocommerce form fields, so additional functions and code where required.

Also I have extended the code to handle the phone field behavior in My Account > Edit Addresses, where customer can make changes to his account data.

Here is the complete code (define your country codes in the first function):

// SETTINGS: The countries codes (2 capital letters) in the array
function defined_countries_for_phone_field(){
return array( 'UK', 'BE', 'GE', 'IT', 'ES' );
}

// Remove "(optional)" from non required "Billing phone" field
add_filter( 'woocommerce_form_field' , 'remove_checkout_optional_fields_label', 10, 4 );
function remove_checkout_optional_fields_label( $field, $key, $args, $value ) {

// Get the defined countries codes
$countries = defined_countries_for_phone_field();

// Get Customer shipping country
$shipping_country = WC()->customer->get_shipping_country();

// Only on checkout page and My account > Edit address for billing phone field
if( 'billing_phone' === $key && ( ( is_wc_endpoint_url( 'edit-address' )
&& ! in_array($shipping_country, $countries) ) || is_checkout() ) ) {
$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
$field = str_replace( $optional, '', $field );
}
return $field;
}

// Make the billing phone field optional (by default)
add_filter( 'woocommerce_billing_fields', 'filter_billing_phone_field', 10, 1 );
function filter_billing_phone_field( $fields ) {

// Get the defined countries codes
$countries = defined_countries_for_phone_field();

// Get Customer shipping country
$shipping_country = WC()->customer->get_shipping_country();

// Only on checkout page and My account > Edit address
if ( ( is_wc_endpoint_url( 'edit-address' )
&& ! in_array($shipping_country, $countries) ) || is_checkout() )
$fields['billing_phone']['required'] = false;

return $fields;
}

// Real time shipping country selection actions
add_action( 'woocommerce_after_order_notes', 'custom_checkout_scripts_and_fields', 10, 1 );
function custom_checkout_scripts_and_fields( $checkout ) {
$required = esc_attr__( 'required', 'woocommerce' );

// Get the defined countries codes
$countries = defined_countries_for_phone_field();

// Hidden field for the phone number validation
echo '<input type="hidden" name="billing_phone_check" id="billing_phone_check" value="0">';
$countries_str = "'".implode( "', '", $countries )."'"; // Formatting countries for jQuery
?>
<script type="text/javascript">
(function($){
var required = '<abbr class="required" title="<?php echo $required; ?>">*</abbr>',
countries = [<?php echo $countries_str; ?>],
location = $('#shipping_country option:selected').val(),
phoneCheck = 'input#billing_phone_check',
phoneField = '#billing_phone_field';

function actionRequire( actionToDo='yes', selector='' ){
if ( actionToDo == 'yes' ) {
$(selector).addClass("validate-required");
$(selector+' label').append(required);
} else {
$(selector).removeClass("validate-required");
$(selector+' label > .required').remove();
}
$(selector).removeClass("woocommerce-validated");
$(selector).removeClass("woocommerce-invalid woocommerce-invalid-required-field");
}

// Default value Once DOM is loaded (with a 300 ms delay)
setTimeout( function(){
actionRequire( 'no', phoneField );
if( $.inArray( location, countries ) >= 0 && $(phoneCheck).val() == '0' ){
actionRequire( 'yes',phoneField );
$(phoneCheck).val('1');
}
}, 300 );

// Live value
$( 'form.checkout' ).on( 'change', '#shipping_country', function(){
var location = $('#shipping_country option:selected').val();
if ( $.inArray( location, countries ) >= 0 && $(phoneCheck).val() == 0 ) {
actionRequire( 'yes' ,phoneField );
$(phoneCheck).val('1');
} else if ( $(phoneCheck).val() == 1 ) {
actionRequire( 'no' ,phoneField );
$(phoneCheck).val('0');
}
});
})(jQuery);
</script>
<?php
}

// Phone number validation, when the field is required
add_action('woocommerce_checkout_process', 'billing_phone_field_process');
function billing_phone_field_process() {
// Check if set, if its not set add an error.
if ( ! $_POST['billing_phone'] && $_POST['billing_phone_check'] == '1' )
wc_add_notice( __( 'Please enter a number phone.' ), 'error' );
}

Code goes in function.php file of your active child theme (or active theme). Tested and works in WooCommerce from version 3.4 and above.

Related:

  • Make checkout phone field optional for specific countries in WooCommerce
  • Remove "(optional)" text from checkout fields in Woocommerce 3.4+

Make checkout phone field optional for specific countries in WooCommerce

You mostly need to use javascript for real time events or live events on client side… The code below is mostly using jQuery and a bit of PHP, to make the billing phone required only when customer select specific countries:

// Making the billing phone field not required (by default)
add_filter( 'woocommerce_billing_fields', 'filter_billing_phone_field', 10, 1 );
function filter_billing_phone_field( $fields ) {
$fields['billing_phone']['required'] = false;
return $fields;
}

// Real time country selection actions
add_action( 'woocommerce_after_order_notes', 'custom_checkout_scripts_and_fields', 10, 1 );
function custom_checkout_scripts_and_fields( $checkout ) {
$required = esc_attr__( 'required', 'woocommerce' );

// HERE set the countries codes (2 capital letters) in this array:
$countries = array( 'UK', 'BE', 'GE', 'IT', 'ES' );

// Hidden field for the phone number validation
echo '<input type="hidden" name="billing_phone_check" id="billing_phone_check" value="0">';
$countries_str = "'".implode( "', '", $countries )."'"; // Formatting countries for jQuery
?>
<script type="text/javascript">
(function($){
var required = '<abbr class="required" title="<?php echo $required; ?>">*</abbr>',
countries = [<?php echo $countries_str; ?>],
location = $('#billing_country option:selected').val(),
phoneCheck = 'input#billing_phone_check';

function actionRequire( actionToDo='yes', selector='' ){
if ( actionToDo == 'yes' ) {
$(selector).addClass("validate-required");
$(selector+' label').append(required);
} else {
$(selector).removeClass("validate-required");
$(selector+' label > .required').remove();
}
$(selector).removeClass("woocommerce-validated");
$(selector).removeClass("woocommerce-invalid woocommerce-invalid-required-field");
}

// Default value when loading
actionRequire( 'no','#billing_phone_field' );
if( $.inArray( location, countries ) >= 0 && $(phoneCheck).val() == '0' ){
actionRequire( 'yes','#billing_phone_field' );
$(phoneCheck).val('1');
}

// Live value
$( 'form.checkout' ).on( 'change', '#billing_country', function(){
var location = $('#billing_country option:selected').val();
if ( $.inArray( location, countries ) >= 0 && $(phoneCheck).val() == 0 ) {
actionRequire( 'yes','#billing_phone_field' );
$(phoneCheck).val('1');
} else if ( $(phoneCheck).val() == 1 ) {
actionRequire( 'no','#billing_phone_field' );
$(phoneCheck).val('0');
}
});
})(jQuery);
</script>
<?php
}

// Phone number validation, when it's visible
add_action('woocommerce_checkout_process', 'billing_phone_field_process');
function billing_phone_field_process() {
// Check if set, if its not set add an error.
if ( ! $_POST['billing_phone'] && $_POST['billing_phone_check'] == '1' )
wc_add_notice( __( 'Please enter a number phone.' ), 'error' );
}

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

Tested and works.

Related (2019): Make Woocommerce checkout phone field optional based on shipping country

How to make a custom field required based on country on WooCommerce checkout?

To make the custom field billing_vat required, when the country is set to Ireland (IE).

Just replace your existing code with: (explanation via comment tags, added to the code)

// Add field
function filter_woocommerce_billing_fields( $fields ) {
$fields['billing_vat'] = array(
'label' => 'VAT Number',
'required' => false,
'type' => 'text',
'class' => array( 'form-row-wide' ),
'priority' => 35,
);

return $fields;
}
add_filter( 'woocommerce_billing_fields', 'filter_woocommerce_billing_fields', 10, 1 );

// Validate
function action_woocommerce_after_checkout_validation( $data, $error ) {
if ( $data['billing_country'] == 'IE' && empty( $data['billing_vat'] ) ) {
$error->add( 'validation', 'Required based on country.' );
}
}
add_action('woocommerce_after_checkout_validation', 'action_woocommerce_after_checkout_validation', 10, 2 );

// jQuery
function action_woocommerce_after_order_notes( $checkout ) {
?>
<script>
(function($) {
$(document).ready(function () {
required_or_optional(); //this calls it on load
$( '#billing_country' ).change( required_or_optional );

function required_or_optional() {
if ( $( '#billing_country' ).val() == 'IE' ) {
// Required
$( '#billing_vat' ).prop( 'required', true );
$( 'label[for="billing_vat"] .optional' ).remove();
$( 'label[for="billing_vat"]' ).append( '<abbr class="required" title="required">*</abbr>' );
} else {
$( '#billing_vat' ).removeProp( 'required' );
$( 'label[for="billing_vat"] .required' ).remove();

// Avoid append this multiple times
if ( $( 'label[for="billing_vat"] .optional' ).length == 0 ) {
$( 'label[for="billing_vat"]' ).append( '<span class="optional">(optional)</span>' );
}
}
}
});
})(jQuery);
</script>
<?php
}
add_action( 'woocommerce_after_order_notes', 'action_woocommerce_after_order_notes', 10, 1 );

// Display on the order edit page (backend)
function action_woocommerce_admin_order_data_after_shipping_address( $order ) {
if ( $value = $order->get_meta( '_billing_vat' ) ) {
echo '<p><strong>' . __( 'Billing VAT', 'woocommerce' ) . ':</strong> ' . $value . '</p>';
}
}
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'action_woocommerce_admin_order_data_after_shipping_address', 10, 1 );

Checkout - Limit the Countries in Billing & Shipping based on Geolocation

OK, I could not get exactly what I was hoping to achieve but got something close

My final code:

/** Restrict Change in Checkout Country based on Geo IP (geolocation)*/
function wpse_287199_woo_checkout_country( $fields ) {
$geoData = WC_Geolocation::geolocate_ip();
$countries = WC()->countries->get_countries();
$fields['billing']['billing_country'] = array(
'type' => 'select',
'label' => __('Country', 'woocommerce'),
'options' => array(
$geoData['country'] => $countries[$geoData['country']]
),
'class' => array(
'form-row-wide',
'address-field',
'update_totals_on_change'
)
);
$fields['shipping']['shipping_country'] = array(
'type' => 'select',
'label' => __('Country', 'woocommerce'),
'options' => array(
$geoData['country'] => $countries[$geoData['country']]
),
'class' => array(
'form-row-wide',
'address-field',
'update_totals_on_change'
)
);
return $fields;
}
add_filter( 'woocommerce_checkout_fields' , 'wpse_287199_woo_checkout_country' );
/** Remove (optional) from country fields and make it non selectable*/
function remove_checkout_optional_fields_label_script() {
// Only on checkout page
if( ! ( is_checkout() && ! is_wc_endpoint_url() ) ) return;

$optional = ' <span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
?>
<script>
jQuery(function($){
// On "update" checkout form event
$(document.body).on('update_checkout', function(){
$('#billing_country_field label > .optional').remove();
$('.woocommerce-checkout #billing_country_field').css('pointer-events', 'none');
$('#shipping_country_field label > .optional').remove();
$('.woocommerce-checkout #shipping_country_field').css('pointer-events', 'none');
});
});
</script>
<?php
}
add_filter( 'wp_footer' , 'remove_checkout_optional_fields_label_script' );
// End of above code

This would make the country field auto populate with Geolocation data and make it non selectable is there such a word? ;)

final result

Any improvement suggestion is very welcome.

Thanks

Make state checkout field optional in Woocommerce

The following code will make the state field optional for all countries in Woocommerce:

add_filter( 'woocommerce_get_country_locale', 'custom_country_locale_state_optional', 10, 1 );
function custom_country_locale_state_optional( $locale ) {
foreach( $locale as $country_code => $state_field ) {
if( isset($locale[$country_code]['state']) ) {
$locale[$country_code]['state']['required'] = false;
}
}
return $locale;
}

Code goes in function.php file of your active child theme (active theme). Tested and works.

Related: Make state checkout field required for a specific country in Woocommerce



Related Topics



Leave a reply



Submit