You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WooCommerce尼日利亚账单城市下拉切换国家后数据异常求助

WooCommerce尼日利亚账单城市下拉切换问题修复

问题描述

现有代码实现了WooCommerce结账页面尼日利亚(NG)地区的自定义账单城市下拉选择功能,切换尼日利亚各州时功能正常,但切换到其他国家后再切回尼日利亚,切换各州时城市数据始终保留旧值,必须刷新页面才能恢复正常。

原实现代码

PHP代码

add_action('wp_footer', 'replace_billing_city_field');
function replace_billing_city_field() {
    $current_country = WC()->customer->get_billing_country();
    if ($current_country === 'NG') {
        $plugin_url = plugin_dir_url(__FILE__);
        $cities_file_url = $plugin_url . 'cities.json';
    ?>
    <script>
    jQuery(document).ready(function($) {
        var billingFieldsContainer = $('form.checkout').find('#billing_country_field, #billing_state_field, #billing_city_field');
        var billingCountryField = billingFieldsContainer.find('select#billing_country');
        var billingStateField = billingFieldsContainer.find('select#billing_state');
        var billingCityField = billingFieldsContainer.find('input#billing_city');
        var billingCitySelectField = $('<select>', {
            'name': billingCityField.attr('name'),
            'id': billingCityField.attr('id'),
            'class': billingCityField.attr('class') 
        });
        function updateBillingCityField() {
            var selectedCountry = billingCountryField.val();
            var selectedState = billingStateField.val();
            if (selectedCountry === 'NG') {
                $.ajax({
                    url: '<?php echo esc_url($cities_file_url); ?>',
                    dataType: 'json',
                    success: function(data) {
                        var states_cities = data['NG'];
                        if (selectedState === '') {
                            billingCitySelectField.html('');
                            billingCityField.replaceWith(billingCitySelectField);
                            billingCityField = billingCitySelectField; // Update the reference to the new select field
                        } else if (states_cities.hasOwnProperty(selectedState)) {
                            var cities = states_cities[selectedState].cities;
                            var options = '';
                            for (var key in cities) {
                                if (cities.hasOwnProperty(key)) {
                                    options += '<option value="' + key + '">' + cities[key] + '</option>';
                                }
                            }
                            billingCitySelectField.html(options);
                            billingCityField.replaceWith(billingCitySelectField);
                            billingCityField = billingCitySelectField; // Update the reference to the new select field
                        } else {
                            billingCitySelectField.replaceWith(billingCityField);
                            billingCityField = billingFieldsContainer.find('input#billing_city'); // Update the reference to the input field
                        }
                        billingCityField.show();
                    }
                });
            } else {
                billingCityField.val('').hide();   
            }
        }
        billingCountryField.on('change', function() {
           updateBillingCityField();       
        });
        billingFieldsContainer.on('change', 'select#billing_state', function() {
           updateBillingCityField();
        });
        updateBillingCityField();
    });
    </script>
    <?php
    }
}

城市数据JSON(cities.json)

{
  "NG": {
    "AB": {
      "name": "Abia",
      "cities": {
        "": "Select a city",
        "City 1": "City 1",
        "City 2": "City 2"
      }
    },
    "LA": {
      "name": "Lagos",
      "cities": {
        "": "Select a city",
        "Agege": "Agege",
        "Ajeromi-Ifelodun": "Ajeromi-Ifelodun"
      }
    },
    "AD": {
      "name": "Adamawa",
      "cities": {
        "": "Select a city",
        "Demsa": "Demsa",
        "Fufore": "Fufore",
        "Ganye": "Ganye",
        "Girei": "Girei",
        "Gombi": "Gombi",
        "Guyuk": "Guyuk",
        "Hong": "Hong",
        "Jada": "Jada",
        "Lamurde": "Lamurde",
        "Madagali": "Madagali",
        "Maiha": "Maiha",
        "Mayo-Belwa": "Mayo-Belwa",
        "Michika": "Michika",
        "Mubi-North": "Mubi-North",
        "Mubi-South": "Mubi-South",
        "Numan": "Numan",
        "Shelleng": "Shelleng",
        "Song": "Song",
        "Toungo": "Toungo",
        "Yola North": "Yola North",
        "Yola South": "Yola South"
      }
    }
  }
}

问题根源

  1. PHP仅在用户当前账单国家为NG时加载JS,切换国家后切回NG时,JS逻辑无法重新初始化。
  2. 切换到非NG国家时,仅隐藏城市字段未恢复原始输入框,导致切回NG时元素引用混乱。
  3. AJAX请求未禁用缓存,可能重复获取旧数据。

修复后的代码

PHP代码

add_action('wp_footer', 'replace_billing_city_field');
function replace_billing_city_field() {
    $plugin_url = plugin_dir_url(__FILE__);
    $cities_file_url = $plugin_url . 'cities.json';
    ?>
    <script>
    jQuery(document).ready(function($) {
        var billingFieldsContainer = $('form.checkout').find('#billing_country_field, #billing_state_field, #billing_city_field');
        var billingCountryField = billingFieldsContainer.find('select#billing_country');
        var billingStateField = billingFieldsContainer.find('select#billing_state');
        
        // 保存原始输入框的模板,用于恢复
        var originalBillingCityInput = $('#billing_city').clone(true);

        function updateBillingCityField() {
            var selectedCountry = billingCountryField.val();
            var selectedState = billingStateField.val();
            var currentCityField = $('#billing_city');

            if (selectedCountry === 'NG') {
                // 禁用AJAX缓存,确保每次获取最新数据
                $.ajax({
                    url: '<?php echo esc_url($cities_file_url); ?>',
                    dataType: 'json',
                    cache: false,
                    success: function(data) {
                        var states_cities = data['NG'];
                        var citySelect = $('<select>', {
                            'name': originalBillingCityInput.attr('name'),
                            'id': originalBillingCityInput.attr('id'),
                            'class': originalBillingCityInput.attr('class')
                        });

                        if (selectedState === '' || !states_cities.hasOwnProperty(selectedState)) {
                            // 无选中州或州不存在,显示空选择框或恢复输入框
                            if (selectedState === '') {
                                citySelect.html('<option value="">Select a city</option>');
                                currentCityField.replaceWith(citySelect);
                            } else {
                                currentCityField.replaceWith(originalBillingCityInput.clone(true));
                            }
                        } else {
                            // 生成对应州的城市选项
                            var cities = states_cities[selectedState].cities;
                            var options = '';
                            for (var key in cities) {
                                if (cities.hasOwnProperty(key)) {
                                    options += '<option value="' + key + '">' + cities[key] + '</option>';
                                }
                            }
                            citySelect.html(options);
                            currentCityField.replaceWith(citySelect);
                        }
                        $('#billing_city').show();
                    }
                });
            } else {
                // 切换到非NG国家,恢复原始输入框并清空显示
                if (currentCityField.is('select')) {
                    currentCityField.replaceWith(originalBillingCityInput.clone(true));
                }
                $('#billing_city').val('').show();
            }
        }

        // 绑定事件,确保元素替换后事件仍有效
        billingCountryField.on('change', updateBillingCityField);
        billingFieldsContainer.on('change', '#billing_state', updateBillingCityField);

        // 页面加载时初始化
        updateBillingCityField();
    });
    </script>
    <?php
}

修复说明

  • 移除PHP中仅NG国家加载JS的判断,让JS始终加载,确保切换国家时逻辑都能触发。
  • 保存原始城市输入框模板,每次需要恢复时克隆使用,避免元素引用混乱。
  • 给AJAX请求添加cache: false,禁用缓存,确保每次获取最新城市数据。
  • 优化字段切换逻辑,切换到非NG国家时强制恢复原始输入框,避免残留下拉框状态。
  • 简化元素引用逻辑,每次操作都直接通过ID获取当前城市字段,避免引用过时元素。

内容的提问来源于stack exchange,提问作者Drizzy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 00:05:11