Adam Luper
Adam Luper

Reputation: 77

Enable/disable a WooCommerce required checkout field based on selected payment method

The answer to the above question helped me, but I still have a problem: Show hide custom Woocommerce checkout field based on selected payment method

I want the Phone field (a field is required) to be displayed when the customer selects the cheque payment gateway, and the mobile field is not displayed and disabled if he selects other payment gateways.

// 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() ) :
    ?>
    <script>
        jQuery(function($){
            var a = 'input[name="payment_method"]',
                b = a + ':checked',
                c = '#billing_phone_field'; // The checkout field <p> container selector

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

            // Initialising: Hide if choosen payment method is "cheque"
            if( $(b).val() !== 'cheque' )
                showHide( c, 'hide' );
            else
                showHide( c );

            // Live event (When payment method is changed): Show or Hide based on "cheque"
            $( 'form.checkout' ).on( 'change', a, function() {
                if( $(b).val() !== 'cheque' )
                    showHide( c, 'hide' );
                else
                    showHide( c );
            });
        });
    </script>
    <?php
    endif;
}

The problem is when I choose other payment gateways besides cheque, even though the Phone field is hidden, it is still validated and displays the error (Billing Phone is a required field) - and this field needs to be filled, I don't want this!

Upvotes: 2

Views: 1304

Answers (1)

LoicTheAztec
LoicTheAztec

Reputation: 253773

The following will do the job, adding a hidden field to handle the billing phone validation when the billing phone field is visible. When the billing phone field is hidden and empty, no validation error will be prompted, allowing placing the order silently:

// Your settings goes in here
function my_checkout_settings()
{
    return array(
        'payment_id'   => 'cheque', // The payment Id
        'field_key_id' => 'billing_phone', // The checkout field key ID
    );
}

// Add a hidden billing input field for phone validation purpose
add_action('woocommerce_billing_fields', 'add_an_hidden_billing_fields');
function add_an_hidden_billing_fields($billing_fields) {
    extract(my_checkout_settings()); // Load your settings

    // Add a hidden input field
    $billing_fields[$field_key_id . '_is_valid'] = array(
        'type' => 'hidden',
        'required' => false,
        'default' => '',
    );

    return $billing_fields;
}

// Disabling conditionally the Billing phone validation
add_action('woocommerce_after_checkout_validation', 'disable_specific_checkout_field_validation_conditionally', 20, 2);
function disable_specific_checkout_field_validation_conditionally($data, $errors) {
    extract(my_checkout_settings()); // Load your settings

    $validation_key =  $field_key_id . '_is_valid'; // The key Id of the hidden field

    if (empty($data[$field_key_id]) && isset($data[$validation_key]) && $data[$validation_key]) {
        $errors->remove($field_key_id . '_required'); // Remove unwanted error for this field
    }
}

// Conditional Show hide billing phone checkout fields based on chosen payment methods
add_action('woocommerce_checkout_init', 'enqueue_checkout_custom_script');
function enqueue_checkout_custom_script() {
    extract(my_checkout_settings()); // Load your settings

    wc_enqueue_js("const a = 'input[name=payment_method]',
        b = a + ':checked',
        c = '#{$field_key_id}',
        d = c + '_field',
        v = c + '_is_valid',
        p = '{$payment_id}';
    
    function triggerShowHide(b, d, p, v) {
        $(b).val() !== p ? $(d).show(200) : $(d).hide(200);
        $(b).val() !== p ? $(v).val('') : $(v).val('1');
    }
    
    // On the first load
     triggerShowHide(b, d, p, v);
    
    // On payment method 'change' live event
    $('form.checkout').on('change', a, function() {
        triggerShowHide(b, d, p, v);
    });");
}

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

Upvotes: 4

Related Questions