Replace the city text field by a dropdown of cities for a specific country in Woocommerce

荒凉一梦 提交于 2019-12-01 23:16:52

Updated (Additional city text field when "Others" is the selected value from the dropdown)

The following code (jQuery powered) will replace the city text field by a custom dropdown of cities for a specific country only and for this specific country, if the city selected value is "Others", an additional text field will appear under the cities dropdown, where customer can enter manually a different city.

The code works for shipping and billing fields independently.

When "Others" is selected for the defined country, the two last functions will:

  • Validate that the city additional field is filled,
  • Save the city value as billing or shipping city value.

The code:

// HERE are is the array of cities for Saudi Arabia (SA)
function get_cities_options(){
    $domain = 'woocommerce'; // The domain text slug

    return array(
        ''          => __('Select a city', $domain),
        'Abhā'      => 'Abhā',      'Abqaiq'    => 'Abqaiq',
        'Al-Baḥah'  => 'Al-Baḥah',  'Al-Dammām' => 'Al-Dammām',
        'Al-Hufūf'  => 'Al-Hufūf',  'Al-Jawf'   => 'Al-Jawf',
        'Al-Kharj'  => 'Al-Kharj',  'Al-Khubar' => 'Al-Khubar',
        'Al-Qaṭīf'  => 'Al-Qaṭīf',  'Al-Ṭaʾif'  => 'Al-Ṭaʾif',
        'ʿArʿar'    => 'ʿArʿar',    'Buraydah'  => 'Buraydah',
        'Dhahran'   => 'Dhahran',   'Ḥāʾil'     => 'Ḥāʾil',
        'Jiddah'    => 'Jiddah','Jīzān'     => 'Jīzān',
        'Khamīs Mushayt'            => 'Khamīs Mushayt',
        'King Khalīd Military City' => 'King Khalīd Military City',
        'Mecca'     => 'Mecca',     'Medina'    => 'Medina',
        'Najrān'    => 'Najrān',    'Ras Tanura'=> 'Ras Tanura',
        'Riyadh'    => 'Riyadh',    'Sakākā'    => 'Sakākā',
        'Tabūk'     => 'Tabūk',     'Yanbuʿ'    => 'Yanbuʿ',
        'Other'     => __('Other cities (not listed)', $domain),
    );
}

// add an additional field
add_filter( 'woocommerce_checkout_fields' , 'additional_checkout_city_field' );
function additional_checkout_city_field( $fields ) {
    // Inline CSS To hide the fields on start
    ?><style> #billing_city2_field.hidden, #shipping_city2_field.hidden {display:none;}</style><?php

    $fields['billing']['billing_city2'] = array(
        'placeholder'   => _x('Other city', 'placeholder', 'woocommerce'),
        'required'  => false,
        'priority'  => 75,
        'class'     => array('form-row-wide hidden'),
        'clear'     => true
    );

    $fields['shipping']['shipping_city2'] = array(
        'placeholder'   => _x('Other city', 'placeholder', 'woocommerce'),
        'required'  => false,
        'priority'  => 75,
        'class'     => array('form-row-wide hidden'),
        'clear'     => true
    );

    return $fields;
}

// Add checkout custom select fields
add_action( 'wp_footer', 'custom_checkout_city_field', 20, 1 );
function custom_checkout_city_field() {
    // Only checkout page
    if( is_checkout() && ! is_wc_endpoint_url() ):

    $country = 'SA'; //  <=== <=== The country code

    $b_city  = 'billing_city';
    $s_city  = 'shipping_city';
    $billing_city_compo    = 'name="'.$b_city.'" id="'.$b_city.'"';
    $shipping_city_compo   = 'name="'.$s_city.'" id="'.$s_city.'"';
    $end_of_field          = ' autocomplete="address-level2" value="">';
    $billing_text_field    = '<input type="text" class="input-text" ' . $billing_city_compo  . $end_of_field;
    $shipping_text_field   = '<input type="text" class="input-text" ' . $shipping_city_compo . $end_of_field;
    $billing_select_field  = '<select ' . $billing_city_compo  . $end_of_field;
    $shipping_select_field = '<select ' . $shipping_city_compo . $end_of_field;

    ?>
    <script type="text/javascript">
    jQuery(function($){
        var a   = <?php echo json_encode( get_cities_options() ); ?>,           fc = 'form.checkout',
            b   = 'billing',                s   = 'shipping',               ci = '_city2',
            bc  = '<?php echo $b_city; ?>', sc = '<?php echo $s_city; ?>',  co = '_country',
            bci = '#'+bc,                   sci = '#'+sc,                   fi = '_field',
            btf = '<?php echo $billing_text_field; ?>',     stf = '<?php echo $shipping_text_field; ?>',
            bsf = '<?php echo $billing_select_field; ?>',   ssf = '<?php echo $shipping_select_field; ?>',
            cc  = '<?php echo $country; ?>';

        // Utility function that fill dynamically the select field options
        function dynamicSelectOptions( type ){
            var select = (type == b) ? bsf : ssf,
                fvalue = (type == b) ? $(bci).val() : $(sci).val();


            $.each( a, function( key, value ){
                selected = ( fvalue == key ) ? ' selected' : '';
                selected = ( ( fvalue == '' || fvalue == undefined ) && key == '' ) ? ' selected' : selected;
                select += '<option value="'+key+'"'+selected+'>'+value+'</option>';
            });
            select += '</select>';

            if ( type == b ) 
                $(bci).replaceWith(select);
            else 
                $(sci).replaceWith(select);
        }

        // Utility function that will show / hide the "country2" additional text field
        function showHideCity2( type, city ){
            var field   = (type == b) ? bci : sci,
                country = $('#'+type+co).val();

            if( country == cc && city == 'Other' && $('#'+type+ci+fi).hasClass('hidden') ){
                $('#'+type+ci+fi).removeClass('hidden');
            } else if( country != cc || ( city != 'Other' && ! $('#'+type+ci+fi).hasClass('hidden') ) ) {
                $('#'+type+ci+fi).addClass('hidden');
                if( country != cc && city == 'Other' ){
                    $(field).val('');
                }
            }
        }

        // On billing country change
        $(fc).on('change', '#'+b+co, function(){
            var bcv = $(bci).val();
            if($(this).val() == cc){
                if( $(bci).attr('type') == 'text' ){
                    dynamicSelectOptions(b);
                    showHideCity2( b, $(bci).val() );
                }
            } else {
                if( $(bci).attr('type') != 'text' ){
                    $(bci).replaceWith(btf);
                    $(bci).val(bcv);
                    showHideCity2( b, $(bci).val() );
                }
            }
        });

        // On shipping country change
        $(fc).on('change', '#'+s+co, function(){
            var scv = $(sc).val();
            if($(this).val() == cc){
                if( $(sci).attr('type') == 'text' ){
                    dynamicSelectOptions(s);
                    showHideCity2( s, $(sci).val() );
                }
            } else {
                if( $(sci).attr('type') != 'text' ){
                    $(sci).replaceWith(stf);
                    $(sci).val(scv);
                    showHideCity2( s, $(sci).val() );
                }
            }
        });

        // On billing city change
        $(fc).on('change', bci, function(){
            showHideCity2( b, $(this).val() );
        });

        // On shipping city change
        $(fc).on('change', sci, function(){
            showHideCity2( s, $(this).val() );
        });
    });
    </script>
    <?php
    endif;
}

// Check  for city 2 fields if billing or/and shipping city fields is "Other"
add_action('woocommerce_checkout_process', 'cbi_cf_process');
function cbi_cf_process() {
    // Check billing city 2 field
    if( isset($_POST['billing_city2']) && empty($_POST['billing_city2']) && $_POST['billing_city'] == 'Other' ){
        wc_add_notice( __( "Please fill in billing city field" ), "error" );
    }

    // Updating shipping city 2 field
    if( isset($_POST['shipping_city2']) && empty($_POST['shipping_city2']) && $_POST['shipping_city'] == 'Other' ){
        wc_add_notice( __( "Please fill in shipping city field" ), "error" );
    }
}

// Updating billing and shipping city fields when using "Other"
add_action( 'woocommerce_checkout_create_order', 'update_order_city_field', 30, 2 );
function update_order_city_field( $order, $posted_data ) {
    // Updating billing city from 'billing_city2'
    if( isset($_POST['billing_city2']) && ! empty($_POST['billing_city2']) && $_POST['billing_city'] == 'Other' ){
        $order->set_billing_city(sanitize_text_field( $_POST['billing_city2'] ) );
    }

    // Updating shipping city
    if( isset($_POST['shipping_city2']) && ! empty($_POST['shipping_city2']) && $_POST['shipping_city'] == 'Other' ){
        $order->set_shipping_city(sanitize_text_field( $_POST['shipping_city'] ) );
    }
}

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

Please Remember that a customer can be in a foreign country outside Soudi Arabia (billing country) and buy something that will be shipped in Soudi Arabia (shipping country).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!