1
votes

In my Wordpress Woocommerce site I need to skip the required validation for billing city field when the user selects a specific billing country.

I have referred answers in the following similar questions but both these don't seem to work on my checkout page. All I did was copy pasting those functions in the functions.php of the active theme and changed the fields and function names accordingly. But the changes or the codes don't appear in the source code of the checkout page and the required validation still works for the countries where the city is not required to be entered.

Referred (Neither of the following answers work for my checkout page)

Make checkout phone field optional for specific countries in WooCommerce

Make Woocommerce checkout phone field optional based on shipping country

My Code

// Making the billing city field not required (by default)
add_filter( 'woocommerce_billing_fields', 'filter_billing_city_field');
function filter_billing_city_field( $fields ) {
    $fields['billing_city']['required'] = false;
    return $fields;
}

// Real time country selection actions
add_action( 'woocommerce_after_order_notes', 'custom_checkout_scripts_and_fields', 8, 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( 'LK');

    // Hidden field for the phone number validation
    echo '<input type="hidden"  name="billing_city_check" id="billing_city_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(),
                cityCheck = 'input#billing_city_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_city_check' );
            if( $.inArray( location, countries ) >= 0  && $(cityCheck).val() == '0' ){
                actionRequire( 'yes','#billing_city_check' );
                $(cityCheck).val('1');
            }

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

// City validation, when it's visible
add_action('woocommerce_checkout_process', 'billing_city_field_process');
function billing_city_field_process() {
    // Check if set, if its not set add an error.
    if ( ! $_POST['billing_city'] && $_POST['billing_city_check'] == '1' )
        wc_add_notice( __( 'Please enter city.' ), 'error' );
}
1

1 Answers

1
votes

Add this code snippet in your activated theme function.php at the end.

add_filter('woocommerce_billing_fields', 'vg_customize_checkout_form');

function vg_customize_checkout_form($fields)
{
    $fields['billing_city']['required'] = false;
    return $fields;
}

#Source: https://github.com/woocommerce/woocommerce/blob/master/includes/class-wc-checkout.php#L845
add_action('woocommerce_after_checkout_validation', 'vg_custom_validation_billing_city', 10, 2);

function vg_custom_validation_billing_city($fields, $error)
{

    if('IN' != $fields['billing_country'] && empty($fields['billing_city'])) {
        $error->add('validation', 'City is required field.');
    }

}

Let's see each hook functionality:

Filter Hook: woocommerce_billing_fields

Official Document:

https://docs.woocommerce.com/document/tutorial-customising-checkout-fields-using-actions-and-filters/#section-8

https://docs.woocommerce.com/document/tutorial-customising-checkout-fields-using-actions-and-filters/#section-2

Purpose: We can alter the predefined properties of the field by overriding the array element as we have overridden the required property of the billing_city field


Action Hook: woocommerce_after_checkout_validation

Official Document:

https://docs.woocommerce.com/wc-apidocs/source-class-WC_Checkout.html#830

Purpose: To add custom code after the cart has been successfully checkout. Here we can add our custom validation and based on validation success or failure we can through error.

Here we verified whether the billing country is not India then the city should be filled. If the user not filled the city for other than India then our custom error City is a required field. will be thrown.


Reference:

  1. https://docs.woocommerce.com/document/tutorial-customising-checkout-fields-using-actions-and-filters/
  2. https://docs.woocommerce.com/wc-apidocs/hook-docs.html