1

In Woocommerce, I am trying to hide the checkout postcode field if a specific city field is selected. I found a working code that hides the billing phone if company field is empty:

add_action( 'woocommerce_after_checkout_form', 'conditionally_hide_show_checkout_field', 9999 );
function conditionally_hide_show_checkout_field() {
wc_enqueue_js( "
  jQuery('#billing_company').keyup(function() {
     if (jQuery(this).val().length == 0) {
        jQuery('#billing_phone').hide();
     } else {
        jQuery('#billing_phone').show();
     }
  }).keyup();
");
}

I don't know how to alter this code to make the required postcode field to be hidden when a specific billing city is selected. Any help is appreciated.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
paiz 92
  • 23
  • 5

2 Answers2

2

It's a bit much more complicated and you will need to define the city in the last function.

The following code handles multiple necessary tasks to show / hide the postcode field based on a specific defined selected city:

// Make postcode field optional
add_filter( 'woocommerce_default_address_fields',  'customizing_checkout_fields' );
function customizing_checkout_fields( $fields ) {
    if( is_checkout() ) {
        $fields['postcode']['required'] = false;
    }
    return $fields;
}

// Replace "(optional)" text by required "*"
add_filter( 'woocommerce_form_field' , 'replace_checkout_optional_by_required', 10, 4 );
function replace_checkout_optional_by_required( $field, $key, $args, $value ) {
    // Only on checkout page for postcode field
    if( is_checkout() && ! is_wc_endpoint_url() && in_array($key, ['billing_postcode', 'shipping_postcode']) ) {
        $optional = '<span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>';
        $required = '<abbr class="required" title="required">*</abbr>';
        $field = str_replace( $optional, $required, $field );
    }
    return $field;
}

// Hidden input fields for Postcode validation when it's visible
add_action( 'woocommerce_after_order_notes', 'checkout_hidden_field_for_validation', 10, 1 );
function checkout_hidden_field_for_validation( $checkout ) {
    // Hidden field for the phone number validation
    echo '<input type="hidden" name="billing_postcode_check" id="billing_postcode_check" value="">
          <input type="hidden" name="shipping_postcode_check" id="shipping_postcode_check" value="">';
}

// Postcode field validation when it's visible
add_action('woocommerce_checkout_process', 'wps_select_checkout_field_process');
function wps_select_checkout_field_process() {
    if( isset($_POST['billing_postcode_check']) && $_POST['billing_postcode_check'] === 'yes' 
    && isset($_POST['billing_postcode']) && empty($_POST['billing_postcode']) ) {
        wc_add_notice( __("The billing postcode field is a required field.", "woocommerce"), 'error' );
    }

    if( isset($_POST['shipping_postcode_check']) && $_POST['shipping_postcode_check'] === 'yes' 
    && isset($_POST['shipping_postcode']) && empty($_POST['shipping_postcode']) ) {
        wc_add_notice( __("The shipping postcode is a required field.", "woocommerce"), 'error' );
    }
}

// Conditional Show hide checkout fields based on chosen payment methods
add_action( 'wp_footer', 'conditionally_show_hide_billing_custom_field' );
function conditionally_show_hide_billing_custom_field(){
    // Only on checkout page
     if ( is_checkout() && ! is_wc_endpoint_url() ) :

     // HERE define the city that will hide postcode field
     $city = 'Paris';

     $required = '&nbsp;<abbr class="required" title="required">*</abbr>';
    ?>
    <script>
        jQuery(function($){
            var bc   = '#billing_city_field input',
                sc   = '#shipping_city_field input',
                bp   = '#billing_postcode_field',
                sp   = '#shipping_postcode_field',
                bpc  = '#billing_postcode_check',
                spc  = '#shipping_postcode_check',
                city = '<?php echo $city; ?>',
                req  = '<?php echo $required; ?>';

            // On "update" checkout form event, replace "(optional)" by required "*"
            $(document.body).on('update_checkout', function(){
                $('#billing_postcode_field label > .optional').replaceWith(req);
            });

            // Function that shows or hide checkout fields
            function showHide( selector = '', action = 'show' ){
                var check = selector == bp ? $(bpc) : $(spc);
                if( action == 'show' )
                    $(selector).show( 200, function(){
                        $(this).addClass("validate-required");
                        check.val('yes');
                    });
                else
                    $(selector).hide( 200, function(){
                        $(this).removeClass("validate-required");
                        check.val('');
                    });
                $(selector).removeClass("woocommerce-validated");
                $(selector).removeClass("woocommerce-invalid woocommerce-invalid-required-field");
            }

            // 1. Initialising (on load): Show/hide based on customer city

            // Billing field
            if( $(bc).val() === city || $(bc).val() == '' )
                showHide( bp, 'hide' );
            else
                showHide( bp );

            // Shipping field
            if( $(sc).val() === city || $(sc).val() == '' )
                showHide( sp, 'hide' );
            else
                showHide( sp );

            // 2. Change live event:  Show/hide based on city change

            $( 'form.checkout' ).on( 'change input', bc, function() { // Billing field
                if( $(bc).val() === city )
                    showHide( bp, 'hide' );
                else
                    showHide( bp );
            });

            $( 'form.checkout' ).on( 'change input', sc, function() { // Shipping field
                if( $(sc).val() === city )
                    showHide( sp, 'hide' );
                else
                    showHide( sp );
            });
        });
    </script>
    <?php
    endif;
}

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

Some related answers:


Hidding billing and shipping postcode on load:

Replace:

            // 1. Initialising (on load): Show/hide based on customer city

            // Billing field
            if( $(bc).val() === city || $(bc).val() == '' )
                showHide( bp, 'hide' );
            else
                showHide( bp );

            // Shipping field
            if( $(sc).val() === city || $(sc).val() == '' )
                showHide( sp, 'hide' );
            else
                showHide( sp );

by:

            // 1. Initialising (on load): Hide postcode

            showHide( bp, 'hide' ); // Billing field
            showHide( sp, 'hide' ); // Shipping field
LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Thank. its working great. just one more question. what if i want to hide postcode by default on page load or if city is not chosen from select. i prefer to hide post code unless user select a city which needs post code. – paiz 92 Jun 03 '20 at 06:29
  • I've tested it before and it didn't work. my default select is a placeholder 'choose a city' and first option of drop-down is 'select city'. when i put value to -1 and select 'select city' it works. but i want to hide postcode when page loads and nothing is selected, and after user select some city, based on city postcode will be shown or not. i don't know the default value of select when nothing is chosen. or do something to prevent postcode to be shown until user click on drop-down or select city. – paiz 92 Jun 03 '20 at 19:34
  • i'm at final steps of building my new site and there is no registered user. i just use billing fields and most of my products will be sold in my city and there is no need of postcode unless customers select another city. if there is no way i prefer to make postcode optional for other cities and hidden for my city and also on page load. – paiz 92 Jun 04 '20 at 04:58
  • @paiz92 See the addition at the end… – LoicTheAztec Jun 04 '20 at 06:42
  • i did that and on page load it is first hidden but just for a millisecond and shows postcode again. seems that it first runs your addition code and after that check if condition on live event and because city is not chosen it shows postcode again. – paiz 92 Jun 04 '20 at 07:15
  • @LoicTheAztec it seems to be like woocommerce_form_field hook is not working for me, returns empy field when tried to echo. Any idea? – Vishnu Oct 30 '20 at 04:16
0

You can do it like this:

$("#billing_city").on("change", function() {
  if ($(this).val() != "") {
    $("#postcode").removeAttr('required');
  } else {
    $("#postcode").prop("required", true);
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="billing_city">
  <option value="">Select City</option>
  <option value="losangeles">LosAngeles</option>
  <option value="newyork">New York</option>
</select>
<input type="text" id="postcode" placeholder="Postcode" required />
matthias_h
  • 11,356
  • 9
  • 22
  • 40
  • thanks for your help. but unfortunatelly it didnt work, i put my code in function.php of my wordpress and it works for company field. but i this one doesnt change anything. – paiz 92 May 31 '20 at 19:59
  • @paiz92 That's strange as it's working here. Do you use different ids? – matthias_h May 31 '20 at 20:03