Commit 278bf85e7c for woocommerce
commit 278bf85e7c0357e50a8d5b3ae8ce31d151a28170
Author: Thomas Roberts <5656702+opr@users.noreply.github.com>
Date: Wed Dec 31 15:15:33 2025 +0000
Add address type prefix to checkout form fields for autofill (#62513)
* Add address type prefix to checkout form fields for autofill
* Prefix address field autocomplete value with address type in block
* Ensure autocomplete attr is reset to correct value after autocomplete
* Add changelog
* Add section tokens to autocomplete attributes per HTML spec
Adds `section-billing` and `section-shipping` tokens to autocomplete
attributes to help browsers distinguish between billing and shipping
address fields. Also adds `name` attribute to Blocks checkout fields.
Format: `section-{type} {type} {field-name}`
Example: `section-billing billing address-level1`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Seghir Nadir <nadir.seghir@gmail.com>
diff --git a/plugins/woocommerce/changelog/wooplug-5541-bug-safari-autocomplete-overwrites-shipping-address-state b/plugins/woocommerce/changelog/wooplug-5541-bug-safari-autocomplete-overwrites-shipping-address-state
new file mode 100644
index 0000000000..03e2cd8c1c
--- /dev/null
+++ b/plugins/woocommerce/changelog/wooplug-5541-bug-safari-autocomplete-overwrites-shipping-address-state
@@ -0,0 +1,4 @@
+Significance: minor
+Type: update
+
+Add prefixes to checkout autocomplete attributes to help with Safari autofill
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/form/utils.ts b/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/form/utils.ts
index 8c168b992e..98e9baa720 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/form/utils.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/base/components/cart-checkout/form/utils.ts
@@ -14,6 +14,7 @@ import type { JSONSchemaType } from 'ajv';
export interface FieldProps {
id: string;
errorId: string;
+ name: string;
label: string;
autoCapitalize: string | undefined;
autoComplete: string | undefined;
@@ -30,9 +31,15 @@ export const createFieldProps = (
): FieldProps => ( {
id: `${ formId }-${ field?.key }`.replaceAll( '/', '-' ), // Replace all slashes with hyphens to avoid invalid HTML ID.
errorId: `${ fieldAddressType }_${ field?.key }`,
+ name: `${ fieldAddressType }_${ field?.key }`,
label: ( field?.required ? field?.label : field?.optionalLabel ) || '',
autoCapitalize: field?.autocapitalize,
- autoComplete: field?.autocomplete,
+ // Prefix autocomplete value with section and address type per HTML spec.
+ // Format: section-<name> [shipping|billing] <autofill-field>
+ // e.g., 'address-level1' becomes 'section-billing billing address-level1'
+ autoComplete: field?.autocomplete
+ ? `section-${ fieldAddressType } ${ fieldAddressType } ${ field.autocomplete }`
+ : undefined,
errorMessage: field?.errorMessage || '',
required: field?.required,
placeholder: field?.placeholder,
diff --git a/plugins/woocommerce/client/legacy/js/frontend/address-autocomplete.js b/plugins/woocommerce/client/legacy/js/frontend/address-autocomplete.js
index 2b7714b586..ba05bb36fb 100644
--- a/plugins/woocommerce/client/legacy/js/frontend/address-autocomplete.js
+++ b/plugins/woocommerce/client/legacy/js/frontend/address-autocomplete.js
@@ -226,6 +226,14 @@ if (
return;
}
+ // Store the original autocomplete value before disabling
+ const originalAutocomplete =
+ input.getAttribute( 'autocomplete' ) || '';
+ input.setAttribute(
+ 'data-original-autocomplete',
+ originalAutocomplete
+ );
+
input.setAttribute( 'autocomplete', 'none' );
input.setAttribute( 'data-lpignore', 'true' );
input.setAttribute( 'data-op-ignore', 'true' );
@@ -274,7 +282,11 @@ if (
return;
}
- input.setAttribute( 'autocomplete', 'address-line1' );
+ // Restore the original autocomplete value
+ const originalAutocomplete =
+ input.getAttribute( 'data-original-autocomplete' ) ||
+ 'address-line1';
+ input.setAttribute( 'autocomplete', originalAutocomplete );
input.setAttribute( 'data-lpignore', 'false' );
input.setAttribute( 'data-op-ignore', 'false' );
input.setAttribute( 'data-1p-ignore', 'false' );
diff --git a/plugins/woocommerce/includes/class-wc-countries.php b/plugins/woocommerce/includes/class-wc-countries.php
index 48de063ac9..c991ee8566 100644
--- a/plugins/woocommerce/includes/class-wc-countries.php
+++ b/plugins/woocommerce/includes/class-wc-countries.php
@@ -1733,11 +1733,20 @@ class WC_Countries {
// Prepend field keys.
$address_fields = array();
+ // Convert type prefix (e.g., 'billing_' or 'shipping_') to address type for autocomplete (e.g., 'billing' or 'shipping').
+ $address_type = rtrim( $type, '_' );
+
foreach ( $fields as $key => $value ) {
if ( 'state' === $key ) {
$value['country_field'] = $type . 'country';
$value['country'] = $country;
}
+ // Prefix autocomplete value with section and address type per HTML spec.
+ // Format: section-<name> [shipping|billing] <autofill-field>
+ // e.g., 'address-level1' becomes 'section-billing billing address-level1'.
+ if ( ! empty( $value['autocomplete'] ) ) {
+ $value['autocomplete'] = 'section-' . $address_type . ' ' . $address_type . ' ' . $value['autocomplete'];
+ }
$address_fields[ $type . $key ] = $value;
}
@@ -1750,7 +1759,7 @@ class WC_Countries {
'type' => 'tel',
'class' => array( 'form-row-wide' ),
'validate' => array( 'phone' ),
- 'autocomplete' => 'tel',
+ 'autocomplete' => 'section-' . $address_type . ' ' . $address_type . ' tel',
'priority' => 100,
);
}
@@ -1760,7 +1769,7 @@ class WC_Countries {
'type' => 'email',
'class' => array( 'form-row-wide' ),
'validate' => array( 'email' ),
- 'autocomplete' => 'email',
+ 'autocomplete' => 'section-' . $address_type . ' ' . $address_type . ' email',
'priority' => 110,
);
}