Commit e15d48cea6a for woocommerce
commit e15d48cea6aad4c45766ecd80fb8b7a932ac6964
Author: Brandon Kraft <public@brandonkraft.com>
Date: Fri Jun 26 16:04:52 2026 -0500
Fix tax state code autocomplete to allow searching by state code (#65882)
* Fix tax state code autocomplete to allow searching by state code
The Tax > Standard rates state field matched only the state name, so
typing a state code (e.g. CA, TX, BD-05) did not surface the matching
state. Generalize the country code-aware autocomplete source into a
shared factory, apply it to the state field, and lower the state
autocomplete minLength from 3 to 2 so two-letter codes can trigger.
* Coerce autocomplete value to string before lowercasing
Some state codes are numeric (e.g. US Minor Outlying Islands, where
PHP integer-coerces the array keys), so they arrive in data.states as
numbers. Calling .toLowerCase() on them threw a TypeError that broke
the state autocomplete for any term matching such an entry. Stringify
value and label before comparing.
* Scope state autocomplete to the selected country
The state field listed every country's states, so a code like AR
surfaced Appenzell Ausserrhoden (CH), Arunachal Pradesh (IN), and
Arezzo (IT) above Arkansas on a US row. Carry the country code through
to data.states and, when the row's country is known, limit suggestions
to that country's states. Falls back to all states when no or unknown
country is entered so the field is never empty (e.g. state typed before
country).
* fix: set explicit html_entity_decode flags for PHP 8.1 compatibility
---------
Co-authored-by: Sam Najian <dev@najian.info>
diff --git a/plugins/woocommerce/changelog/65881-state-code b/plugins/woocommerce/changelog/65881-state-code
new file mode 100644
index 00000000000..b851447c68c
--- /dev/null
+++ b/plugins/woocommerce/changelog/65881-state-code
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix tax state code autocomplete: allow searching by state code and scope suggestions to the selected country
diff --git a/plugins/woocommerce/client/legacy/js/admin/settings-views-html-settings-tax.js b/plugins/woocommerce/client/legacy/js/admin/settings-views-html-settings-tax.js
index 750271d85cb..60e139676fc 100644
--- a/plugins/woocommerce/client/legacy/js/admin/settings-views-html-settings-tax.js
+++ b/plugins/woocommerce/client/legacy/js/admin/settings-views-html-settings-tax.js
@@ -21,16 +21,29 @@
$pagination = $( '#rates-pagination, #rates-bottom-pagination' ),
$search_field = $( '#rates-search .wc-tax-rates-search-field' ),
$submit = $( '.woocommerce-save-button[type=submit]' ),
- countryAutocompleteSource = function( request, response ) {
+ /**
+ * Filter a list of { value, label } items against the autocomplete term,
+ * matching both the stored code (`value`) and the display name (`label`)
+ * so a field holding a code can be found by typing the code, not just the
+ * name. Matches are ranked so the most relevant code matches surface first.
+ *
+ * @param {Array} items List of { value, label } objects to search.
+ * @param {Object} request jQuery UI autocomplete request ({ term }).
+ * @param {Function} response jQuery UI autocomplete response callback.
+ */
+ rankCodeAwareMatches = function( items, request, response ) {
var term = request.term.toLowerCase(),
matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), 'i' ),
- matches = $.grep( data.countries, function( country ) {
- return matcher.test( country.value ) || matcher.test( country.label );
+ matches = $.grep( items, function( item ) {
+ return matcher.test( item.value ) || matcher.test( item.label );
} );
- response( _.sortBy( matches, function( country ) {
- var value = country.value.toLowerCase(),
- label = country.label.toLowerCase();
+ /* Rank: exact code (0), code prefix (1), name prefix (2), name substring (3). */
+ response( _.sortBy( matches, function( item ) {
+ // Some state codes are numeric (e.g. US Minor Outlying Islands),
+ // which arrive as numbers, so coerce to string before comparing.
+ var value = String( item.value ).toLowerCase(),
+ label = String( item.label ).toLowerCase();
if ( value === term ) {
return 0;
@@ -44,6 +57,27 @@
return 3;
} ) );
},
+ countryAutocompleteSource = function( request, response ) {
+ rankCodeAwareMatches( data.countries, request, response );
+ },
+ stateAutocompleteSource = function( request, response ) {
+ // Scope state suggestions to the row's selected country when known,
+ // falling back to all states if no/unknown country is entered yet.
+ var country = String( this.element.closest( 'tr' ).find( 'td.country input' ).val() || '' ).trim().toUpperCase(),
+ states = data.states;
+
+ if ( country ) {
+ var scoped = $.grep( data.states, function( state ) {
+ return state.country === country;
+ } );
+
+ if ( scoped.length ) {
+ states = scoped;
+ }
+ }
+
+ rankCodeAwareMatches( states, request, response );
+ },
WCTaxTableModelConstructor = Backbone.Model.extend({
changes: {},
setRateAttribute: function( rateID, attribute, value ) {
@@ -183,8 +217,8 @@
// Initialize autocomplete for states.
this.$el.find( 'td.state input' ).autocomplete({
- source: data.states,
- minLength: 3
+ source: stateAutocompleteSource,
+ minLength: 2
});
// Postcode and city don't have `name` values by default.
diff --git a/plugins/woocommerce/includes/admin/settings/class-wc-settings-tax.php b/plugins/woocommerce/includes/admin/settings/class-wc-settings-tax.php
index 662c3305141..4b78ff09885 100644
--- a/plugins/woocommerce/includes/admin/settings/class-wc-settings-tax.php
+++ b/plugins/woocommerce/includes/admin/settings/class-wc-settings-tax.php
@@ -197,11 +197,12 @@ class WC_Settings_Tax extends WC_Settings_Page {
}
$states = array();
- foreach ( WC()->countries->get_allowed_country_states() as $label ) {
- foreach ( $label as $code => $state ) {
+ foreach ( WC()->countries->get_allowed_country_states() as $country_code => $country_states ) {
+ foreach ( $country_states as $code => $state ) {
$states[] = array(
- 'value' => $code,
- 'label' => esc_js( html_entity_decode( $state ) ),
+ 'value' => $code,
+ 'label' => esc_js( html_entity_decode( $state, ENT_QUOTES ) ),
+ 'country' => $country_code,
);
}
}