1

Based on the code from the answer here Show sub Areas dropdown based on chosen city in WooCommerce checkout, I successfully made some changes in the code to fit my needs:

function cities_areas_settings() {
    $text_domain = 'woocommerce';
    return array(
        __('', $text_domain) => array( 
        ),
        __('Test', $text_domain) => array( 
            __('Street 2', $text_domain),
            __('Street 3', $text_domain),
            __('Street 4', $text_domain),
        ),
        __('Test1', $text_domain) => array(
            __('Street 5', $text_domain),
            __('Street 6', $text_domain),
        ),
        __('Test2', $text_domain) => array( 
            __('Street 7', $text_domain),
            __('Street 8', $text_domain),
        ),
        __('Test3', $text_domain) => array(
            __('Street 9', $text_domain),
            __('Street 10', $text_domain),
        ),
    );
}

add_filter('woocommerce_checkout_fields', 'custom_checkout_fields');
function custom_checkout_fields($fields) {
    $text_domain = 'woocommerce';
    $option_cities = array();
    $select_areas = array('' => __('Select your street', $text_domain)); // 
    $test_areas = array('' => __('Select your street', $text_domain)); // 
    $test1_areas = array('' => __('Select your street', $text_domain)); // 
    $test2_areas = array('' => __('Select your street', $text_domain)); 

    foreach (cities_areas_settings() as $city => $zone) {
        $option_cities[$city] = $city; 

        if ($city === '') {
            foreach ($zone as $area) { 
                $select_areas[$area] = $area; 
            }
             } elseif ($city === 'Test') {
            foreach ($zone as $area) { 
                $test_areas[$area] = $area; 
            }
        } elseif ($city === 'Test1') { 
            foreach ($zone as $area) { 
                $test1_areas[$area] = $area; 
            }
        } elseif ($city === 'Test2') {
            foreach ($zone as $area) { 
                $test2_areas[$area] = $area; 
            }
        }
    }

    $fields['billing']['billing_city']['type'] = 'select'; 
    $fields['billing']['billing_city']['class'] = array('form-row-first');
    $fields['billing']['billing_city']['input_class'] = array('state_select');
    $fields['billing']['billing_city']['options'] = $option_cities;

    $fields['shipping']['shipping_city']['type'] = 'select'; 
    $fields['shipping']['shipping_city']['class'] = array('form-row-first');
    $fields['shipping']['shipping_city']['input_class'] = array('state_select');
    $fields['shipping']['shipping_city']['options'] = $option_cities;

    $fields['billing']['billing_address_1'] = array(
        'type' => 'select',
        'label' => __('Street', $text_domain),
        'class' => array('form-row-last'),
        'input_class' => array('state_select'),
        'options' => $select_areas,
        'required' => true,
        'default' => '',
        'priority' => 50,
    );

    $fields['shipping']['shipping_address_1'] = array(
        'type' => 'select',
        'label' => __('Street', $text_domain),
        'class' => array('form-row-last'), 
        'input_class' => array('state_select'),
        'options' => $select_areas,
        'required' => true,
        'default' => '',
        'priority' => 50,
    );

    return $fields;
}

add_action('wp_footer', 'custom_checkout_js_script');
function custom_checkout_js_script() {
    if (is_checkout() && !is_wc_endpoint_url()) :
        $text_domain = 'woocommerce';
        $test_areas = array('' => __('Select your street', $text_domain)); 
        $test1_areas = array('' => __('Select your street', $text_domain));
        $test2_areas = array('' => __('Select your street', $text_domain)); 
        $test3_areas = array('' => __('Select your street', $text_domain)); 
        $settings = cities_areas_settings(); 
        
        foreach ($settings['Test'] as $area) { 
            $test_areas[$area] = $area; 
        }
        foreach ($settings['Test1'] as $area) { 
            $test1_areas[$area] = $area; 
        }

        foreach ($settings['Test2'] as $area) { 
            $test2_areas[$area] = $area; 
        }

        foreach ($settings['Test3'] as $area) {
            $test3_areas[$area] = $area; 
        }
        ?>
        <script language="javascript">
            jQuery(function($) {
                var a = 'select[name="billing_city"]',
                    b = 'select[name="billing_address_1"]',
                    l = <?php echo json_encode($test_areas); ?>,
                    o = <?php echo json_encode($test1_areas); ?>,
                    r = <?php echo json_encode($test2_areas); ?>,
                    i = <?php echo json_encode($test3_areas); ?>,
                    s = $(b).html();

                function dynamicSelectOptions(opt) {
                    var options = '';
                    $.each(opt, function(key, value) {
                        options += '<option value="' + key + '">' + value + '</option>';
                    });
                    $(b).html(options);
                }
                
                if ($(a).val() === 'Test') {
                    dynamicSelectOptions(l);
                } else  if ($(a).val() === 'Test1') {
                    dynamicSelectOptions(o);
                } else if ($(a).val() === 'Test2') { 
                    dynamicSelectOptions(r);
                } else if ($(a).val() === 'Test3') {
                    dynamicSelectOptions(i);
                }

                console.log($(a).val());

                $('form.woocommerce-checkout').on('change', a, function() { 
                    console.log($(this).val());
                    if ($(this).val() === 'Test') {
                        dynamicSelectOptions(l);
                    } else if ($(this).val() === 'Test1') {
                        dynamicSelectOptions(o);
                    } else if ($(this).val() === 'Test2') { 
                        dynamicSelectOptions(r);
                    } else if ($(this).val() === 'Test3') {
                        dynamicSelectOptions(i);
                    } else {
                        $(b).html(s);
                    }
                });
            });
        </script>

        <script language="javascript">
            jQuery(function($) {
                var a = 'select[name="shipping_city"]',
                    b = 'select[name="shipping_address_1"]',
                    l = <?php echo json_encode($test_areas); ?>,
                    o = <?php echo json_encode($test1_areas); ?>,
                    r = <?php echo json_encode($test2_areas); ?>,
                    i = <?php echo json_encode($test3_areas); ?>,
                    s = $(b).html();

                function dynamicSelectOptions(opt) {
                    var options = '';
                    $.each(opt, function(key, value) {
                        options += '<option value="' + key + '">' + value + '</option>';
                    });
                    $(b).html(options);
                }
                
                if ($(a).val() === 'Test') {
                    dynamicSelectOptions(l);
                } else if ($(a).val() === 'Test1') {
                    dynamicSelectOptions(o);
                } else if ($(a).val() === 'Test2') { 
                    dynamicSelectOptions(r);
                } else if ($(a).val() === 'Test3') {
                    dynamicSelectOptions(i);
                }

                console.log($(a).val());

                $('form.woocommerce-checkout').on('change', a, function() { 
                    console.log($(this).val());
                    if ($(this).val() === 'Test') {
                        dynamicSelectOptions(l);
                    } else if ($(this).val() === 'Test1') {
                        dynamicSelectOptions(o);
                    } else if ($(this).val() === 'Test2') { 
                        dynamicSelectOptions(r);
                    } else if ($(this).val() === 'Test3') {
                        dynamicSelectOptions(i);
                    } else {
                        $(b).html(s);
                    }
                });
            });
        </script>
    <?php
    endif;
}

The code works correctly on the checkout page.

Now I would display those selectable fields in the customer My Account Edit Address section and wake them work just like in the checkout page.

I looked at the answer here Change WooCommerce city fields to a dropdown in frontend and admin, but I can't figure out how to do it.

I tried to add the following hooks in the code:

add_filter( 'woocommerce_default_address_fields' , 'custom_override_default_city_fields' );
add_filter('woocommerce_admin_billing_fields', 'admin_order_pages_city_fields');
add_filter('woocommerce_admin_shipping_fields', 'admin_order_pages_city_fields');
add_filter( 'woocommerce_customer_meta_fields', 'custom_override_user_city_fields' );

But it is not working. How could I make those fields be displayed in the customer's profile?

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
brc
  • 21
  • 1
  • The rule in Stack Overflow is one question at the time, so you will ask a new question for the admin area part, later on. – LoicTheAztec Jul 05 '23 at 20:29

1 Answers1

0

The code below is just For My Account Edit Address.

The rule in Stack Overflow is one question at the time, so you will ask a new question for the admin area.

The hook woocommerce_checkout_fields only target checkout fields. TO target at the same time, Checkout and My account Address fields, you need to use:

  • woocommerce_billing_fields (for billing fields)
  • woocommerce_shipping_fields (for shipping fields)

For the jQuery code, the selector form is different in My Account Edit Address.

I have revised completely your code:

// Settings
function cities_areas_settings() {
    $text_domain = 'woocommerce';
    return array(
        ''      => array( 
        ),
        'Test'  => array( 
            __('Street 2', $text_domain),
            __('Street 3', $text_domain),
            __('Street 4', $text_domain),
        ),
        'Test1' => array(
            __('Street 5', $text_domain),
            __('Street 6', $text_domain),
        ),
        'Test2' => array( 
            __('Street 7', $text_domain),
            __('Street 8', $text_domain),
        ),
        'Test3' => array(
            __('Street 9', $text_domain),
            __('Street 10', $text_domain),
        ),
    );
}

// Utility function
function get_initial_options_arrays() {
    $text_domain = 'woocommerce';
    return array(
        'text_domain'   => 'woocommerce',
        'option_cities' => array('' => __('Select your City', $text_domain)),
        'select_areas'  => array('' => __('Select your street', $text_domain)),
        'test_areas'    => array('' => __('Select your street', $text_domain)),
        'test1_areas'   => array('' => __('Select your street', $text_domain)),
        'test2_areas'   => array('' => __('Select your street', $text_domain)),
        'test3_areas'   => array('' => __('Select your street', $text_domain)),
    );
}

// Utility function
function get_basic_options_fields() {
    extract(get_initial_options_arrays());

    foreach (cities_areas_settings() as $city => $zone) {
        $option_cities[$city] = $city; 

        if ($city === '') {
            foreach ($zone as $area) { 
                $select_areas[$area] = $area; 
            }
        } 
    }
    return array( 'option_cities' => $option_cities, 'select_areas' => $select_areas );
}

// Billing fields
add_filter('woocommerce_billing_fields', 'custom_billing_fields');
function custom_billing_fields($fields) {
    extract(get_initial_options_arrays());
    extract(get_basic_options_fields());

    $fields['billing_city']['type'] = 'select'; 
    $fields['billing_city']['class'] = array('form-row-first');
    $fields['billing_city']['input_class'] = array('state_select');
    $fields['billing_city']['options'] = $option_cities;

    $fields['billing_address_1'] = array(
        'type' => 'select',
        'label' => __('Street', $text_domain),
        'class' => array('form-row-last'),
        'input_class' => array('state_select'),
        'options' => $select_areas,
        'required' => true,
        'default' => '',
        'priority' => 50,
    );

    return $fields;
}

// Shipping fields
add_filter('woocommerce_shipping_fields', 'custom_shipping_fields');
function custom_shipping_fields($fields) {
    extract(get_initial_options_arrays());
    extract(get_basic_options_fields());

    $fields['shipping']['shipping_city']['type'] = 'select'; 
    $fields['shipping']['shipping_city']['class'] = array('form-row-first');
    $fields['shipping']['shipping_city']['input_class'] = array('state_select');
    $fields['shipping']['shipping_city']['options'] = $option_cities;

    $fields['shipping']['shipping_address_1'] = array(
        'type' => 'select',
        'label' => __('Street', $text_domain),
        'class' => array('form-row-last'), 
        'input_class' => array('state_select'),
        'options' => $select_areas,
        'required' => true,
        'default' => '',
        'priority' => 50,
    );

    return $fields;
}

// Jquery code
add_action('wp_footer', 'custom_checkout_js_script');
function custom_checkout_js_script() {
    if ( ( is_checkout() && !is_wc_endpoint_url() ) || is_wc_endpoint_url( 'edit-address' ) ) :
        extract(get_initial_options_arrays());
        $settings = cities_areas_settings(); 
        
        foreach ($settings['Test'] as $area) { 
            $test_areas[$area] = $area; 
        }
        foreach ($settings['Test1'] as $area) { 
            $test1_areas[$area] = $area; 
        }
        foreach ($settings['Test2'] as $area) { 
            $test2_areas[$area] = $area; 
        }
        foreach ($settings['Test3'] as $area) {
            $test3_areas[$area] = $area; 
        }
        ?>
        <script id="custom-js" language="javascript">
            jQuery(function($) {
                var a = 'select[name="billing_city"]',
                    b = 'select[name="billing_address_1"]',
                    c = 'select[name="shipping_city"]',
                    d = 'select[name="shipping_address_1"]',
                    l = <?php echo json_encode($test_areas); ?>,
                    o = <?php echo json_encode($test1_areas); ?>,
                    r = <?php echo json_encode($test2_areas); ?>,
                    i = <?php echo json_encode($test3_areas); ?>,
                    w = '<?php echo is_checkout() ? 'form.woocommerce-checkout' : 'form'; ?>',
                    s = $(b).html(),
                    t = $(d).html();

                function dynamicSelectOptions(opt, sel) {
                    var options = '';
                    $.each(opt, function(key, value) {
                        options += '<option value="' + key + '">' + value + '</option>';
                    }); 
                    $(sel).html(options);
                }
                
                function dynamicSelectOptionsApply( val, e, l, o, r, i, f = false ) {
                    if (val === 'Test') {
                        dynamicSelectOptions(l, e);
                    } else  if (val === 'Test1') {
                        dynamicSelectOptions(o, e);
                    } else if (val === 'Test2') { 
                        dynamicSelectOptions(r, e);
                    } else if (val === 'Test3') {
                        dynamicSelectOptions(i, e);
                    } else if ( f !== false ) {
                        $(e).html(s);
                    }
                }
                // On start after DOM is loaded
                dynamicSelectOptionsApply($(a).val(), b, l, o, r, i );
                dynamicSelectOptionsApply($(c).val(), d, l, o, r, i );

                // On change event
                $(w).on('change', a, function() { 
                    dynamicSelectOptionsApply( $(this).val(), b, l, o, r, i, s );
                })
                $(w).on('change', c, function() { 
                    dynamicSelectOptionsApply( $(this).val(), d, l, o, r, i, t );
                });
            });
        </script>
    <?php
    endif;
    echo '<pre> endpoint_url "edit-address": ' . print_r(is_wc_endpoint_url( 'edit-address' )) . '</pre>';
}

Tested and works on checkout and on My account Edit Address

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Thank you very much for your help! Unfortunately, the code does not work correctly. Checkout page: - in the invoicing area of the order in Checkout page, the fields are displayed correctly, but the error "Internal Server Error" appears when placing the order. - in the delivery area, the city and the street are not selectable fields and there is an additional field that has the text "array" inside - the error appears in the delivery area /wp-includes/formatting.php on line 1098 – brc Jul 06 '23 at 10:16
  • Customer account: - in the billing area, everything works correctly (including saving the information after selecting the city and street). The only problem (if this were a problem) would be that when re-editing the profile and completing the order, the street no longer appears as selected (not being a big problem, you can go without it). - in the delivery area, the city and the street are not selectable fields and an additional field has appeared (everything the same as in the shipping area of the Checkout page) – brc Jul 06 '23 at 10:18
  • I will check that when I will have some time for it… But you have the right hooks and the right way to make it work for checkout and my account pages. – LoicTheAztec Jul 06 '23 at 10:32