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" } } } }
问题根源
- PHP仅在用户当前账单国家为NG时加载JS,切换国家后切回NG时,JS逻辑无法重新初始化。
- 切换到非NG国家时,仅隐藏城市字段未恢复原始输入框,导致切回NG时元素引用混乱。
- 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
相关产品推荐
相关产品推荐

