Commit a99b4813ef5 for woocommerce
commit a99b4813ef5d4c87ebd8d9899b5563191be26ffd
Author: Jorge A. Torres <jorge.torres@automattic.com>
Date: Fri Jul 3 12:26:26 2026 +0100
Warn when additional checkout fields are registered too early (#66172)
diff --git a/docs/block-development/extensible-blocks/cart-and-checkout-blocks/additional-checkout-fields.md b/docs/block-development/extensible-blocks/cart-and-checkout-blocks/additional-checkout-fields.md
index df738bdb8a1..9111fa6e1f7 100644
--- a/docs/block-development/extensible-blocks/cart-and-checkout-blocks/additional-checkout-fields.md
+++ b/docs/block-development/extensible-blocks/cart-and-checkout-blocks/additional-checkout-fields.md
@@ -199,7 +199,11 @@ There are plans to expand this list, but for now these are the types available.
To register additional checkout fields you must use the `woocommerce_register_additional_checkout_field` function.
-It is recommended to run this function after the `woocommerce_init` action.
+:::note
+
+Register fields on the `woocommerce_init` action (or later). Registering earlier can cause initialization and translation issues.
+
+:::
The registration function takes an array of options describing your field. Some field types take additional options.
diff --git a/plugins/woocommerce/changelog/issue-64592-checkout-fields-textdomain-too-early b/plugins/woocommerce/changelog/issue-64592-checkout-fields-textdomain-too-early
new file mode 100644
index 00000000000..8f5b0169cef
--- /dev/null
+++ b/plugins/woocommerce/changelog/issue-64592-checkout-fields-textdomain-too-early
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Warn when additional checkout fields are registered before the woocommerce_init action, which can load translations too early.
diff --git a/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php b/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php
index 5e87b2f5504..458c98959b5 100644
--- a/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php
+++ b/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php
@@ -189,6 +189,11 @@ class CheckoutFields {
* @return WP_Error|void True if the field was registered, a WP_Error otherwise.
*/
public function register_checkout_field( $options ) {
+ // Warn when fields are registered before `after_setup_theme`. Registering that early can cause problems, such as loading translations before they're ready.
+ if ( ! did_action( 'after_setup_theme' ) && ! doing_action( 'after_setup_theme' ) ) {
+ _doing_it_wrong( 'woocommerce_register_additional_checkout_field', 'Additional checkout fields should be registered on the woocommerce_init action or later.', '11.0.0' );
+ }
+
// Check the options and show warnings if they're not supplied. Return early if an error that would prevent registration is encountered.
if ( false === $this->validate_options( $options ) ) {
return;
diff --git a/plugins/woocommerce/tests/e2e/test-plugins/blocks/additional-checkout-fields.php b/plugins/woocommerce/tests/e2e/test-plugins/blocks/additional-checkout-fields.php
index 8c64fd01d65..ae2bfcf214d 100644
--- a/plugins/woocommerce/tests/e2e/test-plugins/blocks/additional-checkout-fields.php
+++ b/plugins/woocommerce/tests/e2e/test-plugins/blocks/additional-checkout-fields.php
@@ -14,7 +14,7 @@ class Additional_Checkout_Fields_Test_Helper {
public function __construct() {
add_action( 'plugins_loaded', array( $this, 'enable_custom_checkout_fields' ) );
add_action( 'plugins_loaded', array( $this, 'disable_custom_checkout_fields' ) );
- add_action( 'woocommerce_loaded', array( $this, 'register_custom_checkout_fields' ) );
+ add_action( 'woocommerce_init', array( $this, 'register_custom_checkout_fields' ) );
}
/**
diff --git a/plugins/woocommerce/tests/php/src/Blocks/Domain/Services/CheckoutFieldsTest.php b/plugins/woocommerce/tests/php/src/Blocks/Domain/Services/CheckoutFieldsTest.php
index 394ead84ef6..678ec6ec342 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/Domain/Services/CheckoutFieldsTest.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/Domain/Services/CheckoutFieldsTest.php
@@ -188,4 +188,30 @@ class CheckoutFieldsTest extends WP_UnitTestCase {
$this->assertArrayHasKey( 'plugin-namespace/gov-id', $fields );
$this->assertArrayNotHasKey( 'namespace/vat-number', $fields );
}
+
+ /**
+ * Registering a field before after_setup_theme warns the developer.
+ */
+ public function test_registering_before_after_setup_theme_triggers_notice() {
+ $this->setExpectedIncorrectUsage( 'woocommerce_register_additional_checkout_field' );
+
+ $saved_action = $GLOBALS['wp_actions']['after_setup_theme'] ?? null;
+ unset( $GLOBALS['wp_actions']['after_setup_theme'] );
+
+ try {
+ woocommerce_register_additional_checkout_field(
+ array(
+ 'id' => 'test-namespace/early-field',
+ 'label' => 'Early field',
+ 'location' => 'contact',
+ )
+ );
+ } finally {
+ if ( null !== $saved_action ) {
+ // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Restore the count cleared above to simulate registering before after_setup_theme.
+ $GLOBALS['wp_actions']['after_setup_theme'] = $saved_action;
+ }
+ __internal_woocommerce_blocks_deregister_checkout_field( 'test-namespace/early-field' );
+ }
+ }
}