Commit 5f4e924e6f9 for woocommerce
commit 5f4e924e6f9fc7aca7aeec4321e935f9361555d6
Author: Seghir Nadir <nadir.seghir@gmail.com>
Date: Mon Jul 27 13:28:32 2026 +0200
Fix show_in_order_confirmation not hiding address fields (#66899)
* Fix show_in_order_confirmation not hiding address fields consistently
* Add changelog entries for the order confirmation address fields fix
* Remove stale PHPStan baseline entry fixed by the hook docblock correction
* test: move field deregister calls to tearDown in CheckoutFieldsFrontendTest
Fields registered during a test are now tracked in $registered_fields
and always deregistered in tearDown(), even when a test assertion fails.
A register_checkout_field() helper method handles both registration and tracking.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
diff --git a/plugins/woocommerce/changelog/fix-additional-checkout-fields-order-confirmation-address b/plugins/woocommerce/changelog/fix-additional-checkout-fields-order-confirmation-address
new file mode 100644
index 00000000000..0b52e82d3ed
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-additional-checkout-fields-order-confirmation-address
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Hide additional address fields with show_in_order_confirmation set to false from the order confirmation block theme thank you page, classic theme order details, and My Account order details.
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 770f1917c48..d2a79439e1f 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -53499,12 +53499,6 @@ parameters:
count: 1
path: src/Blocks/Domain/Package.php
- -
- message: '#^@param tag must not be named \$this\. Choose a descriptive alias, for example \$instance\.$#'
- identifier: phpDoc.parseError
- count: 1
- path: src/Blocks/Domain/Services/CheckoutFields.php
-
-
message: '#^Instanceof between WC_Data and WC_Data will always evaluate to true\.$#'
identifier: instanceof.alwaysTrue
@@ -53553,24 +53547,6 @@ parameters:
count: 1
path: src/Blocks/Domain/Services/CheckoutFields.php
- -
- message: '#^PHPDoc tag @param has invalid value \(CheckoutFields \$this The CheckoutFields instance\.\)\: Unexpected token "\$this", expected variable at offset 732 on line 14$#'
- identifier: phpDoc.parseError
- count: 1
- path: src/Blocks/Domain/Services/CheckoutFields.php
-
- -
- message: '#^PHPDoc tag @param has invalid value \(bool Whether the field should be shown\.\)\: Unexpected token "Whether", expected variable at offset 333 on line 10$#'
- identifier: phpDoc.parseError
- count: 1
- path: src/Blocks/Domain/Services/CheckoutFields.php
-
- -
- message: '#^Parameter \#2 \$callback of function array_filter expects \(callable\(mixed\)\: bool\)\|null, Closure\(mixed\)\: array given\.$#'
- identifier: argument.type
- count: 1
- path: src/Blocks/Domain/Services/CheckoutFields.php
-
-
message: '#^Parameter \#2 \.\.\.\$values of function sprintf expects bool\|float\|int\|string\|null, array given\.$#'
identifier: argument.type
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/BillingAddress.php b/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/BillingAddress.php
index a581951de45..154b31816af 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/BillingAddress.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/BillingAddress.php
@@ -36,7 +36,15 @@ class BillingAddress extends AbstractOrderConfirmationBlock {
$controller = Package::container()->get( CheckoutFields::class );
$custom = $this->render_additional_fields(
- $controller->get_order_additional_fields_with_values( $order, 'address', 'billing', 'view' )
+ $controller->filter_fields_for_order_confirmation(
+ $controller->get_order_additional_fields_with_values( $order, 'address', 'billing', 'view' ),
+ array(
+ 'caller' => 'BillingAddress::render_content',
+ 'order' => $order,
+ 'permission' => $permission,
+ 'attributes' => $attributes,
+ )
+ )
);
return $address . $phone . $custom;
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/ShippingAddress.php b/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/ShippingAddress.php
index ca23994802d..d589befe5a7 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/ShippingAddress.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/OrderConfirmation/ShippingAddress.php
@@ -36,7 +36,15 @@ class ShippingAddress extends AbstractOrderConfirmationBlock {
$controller = Package::container()->get( CheckoutFields::class );
$custom = $this->render_additional_fields(
- $controller->get_order_additional_fields_with_values( $order, 'address', 'shipping', 'view' )
+ $controller->filter_fields_for_order_confirmation(
+ $controller->get_order_additional_fields_with_values( $order, 'address', 'shipping', 'view' ),
+ array(
+ 'caller' => 'ShippingAddress::render_content',
+ 'order' => $order,
+ 'permission' => $permission,
+ 'attributes' => $attributes,
+ )
+ )
);
return $address . $phone . $custom;
diff --git a/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php b/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php
index 458c98959b5..0ae6b47fc8e 100644
--- a/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php
+++ b/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php
@@ -1401,13 +1401,16 @@ class CheckoutFields {
* WC_Email::additional_checkout_fields
* WC_Email::additional_address_fields
* CheckoutFieldsFrontend::render_order_other_fields
+ * CheckoutFieldsFrontend::render_order_address_fields
* AdditionalFields::render_content
+ * BillingAddress::render_content
+ * ShippingAddress::render_content
*
- * @param bool Whether the field should be shown.
- * @param array $field Field data.
- * @param array $fields All fields for better context when field should be shown or hidden based on other fields values.
- * @param array $context Additional context for the filter. Data depends in which method filter_fields_for_order_confirmation is called.
- * @param CheckoutFields $this The CheckoutFields instance.
+ * @param bool $show_field Whether the field should be shown.
+ * @param array $field Field data.
+ * @param array $fields All fields for better context when field should be shown or hidden based on other fields values.
+ * @param array $context Additional context for the filter. Data depends in which method filter_fields_for_order_confirmation is called.
+ * @param CheckoutFields $instance The CheckoutFields instance.
* @since 10.1.0
*/
return apply_filters( 'woocommerce_filter_fields_for_order_confirmation', ! empty( $field['show_in_order_confirmation'] ), $field, $fields, $context, $this );
diff --git a/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldsFrontend.php b/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldsFrontend.php
index ba057f971a4..b50a0b57b82 100644
--- a/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldsFrontend.php
+++ b/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFieldsFrontend.php
@@ -78,8 +78,18 @@ class CheckoutFieldsFrontend {
* @param WC_Order $order Order object.
*/
public function render_order_address_fields( $address_type, $order ) {
+ $fields = $this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'address', $address_type, 'view' );
+
+ $context = array(
+ 'caller' => 'CheckoutFieldsFrontend::render_order_address_fields',
+ 'address_type' => $address_type,
+ 'order' => $order,
+ );
+
+ $fields = $this->checkout_fields_controller->filter_fields_for_order_confirmation( $fields, $context );
+
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- echo $this->render_additional_fields( $this->checkout_fields_controller->get_order_additional_fields_with_values( $order, 'address', $address_type, 'view' ) );
+ echo $this->render_additional_fields( $fields );
}
/**
diff --git a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/OrderConfirmation/BillingAddress.php b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/OrderConfirmation/BillingAddress.php
new file mode 100644
index 00000000000..8e5c63cc48d
--- /dev/null
+++ b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/OrderConfirmation/BillingAddress.php
@@ -0,0 +1,97 @@
+<?php declare( strict_types = 1 );
+
+namespace Automattic\WooCommerce\Tests\Blocks\BlockTypes\OrderConfirmation;
+
+use Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation\BillingAddress as BillingAddressBlock;
+use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
+use Automattic\WooCommerce\Blocks\Package;
+
+/**
+ * Test BillingAddress block class.
+ */
+final class BillingAddress extends \WP_UnitTestCase {
+ /**
+ * Field id registered for the duration of a test.
+ *
+ * @var string
+ */
+ private $field_id = 'plugin-namespace/billing-confirmation-field';
+
+ /**
+ * Tear down test fixtures.
+ */
+ public function tear_down() {
+ __internal_woocommerce_blocks_deregister_checkout_field( $this->field_id );
+ parent::tear_down();
+ }
+
+ /**
+ * @testdox Additional address field values with show_in_order_confirmation set to false are hidden from the block.
+ */
+ public function test_hides_field_when_show_in_order_confirmation_is_false(): void {
+ woocommerce_register_additional_checkout_field(
+ array(
+ 'id' => $this->field_id,
+ 'label' => 'Hidden on confirmation',
+ 'location' => 'address',
+ 'show_in_order_confirmation' => false,
+ )
+ );
+
+ $order = $this->create_order_with_field_value( 'secret value' );
+
+ $this->assertStringNotContainsString( 'secret value', $this->render( $order ) );
+ }
+
+ /**
+ * @testdox Additional address field values with show_in_order_confirmation set to true (the default) are shown in the block.
+ */
+ public function test_shows_field_when_show_in_order_confirmation_is_true(): void {
+ woocommerce_register_additional_checkout_field(
+ array(
+ 'id' => $this->field_id,
+ 'label' => 'Shown on confirmation',
+ 'location' => 'address',
+ )
+ );
+
+ $order = $this->create_order_with_field_value( 'visible value' );
+
+ $this->assertStringContainsString( 'visible value', $this->render( $order ) );
+ }
+
+ /**
+ * Create an order placed via the Store API with a value persisted for the billing group of the test field.
+ *
+ * @param string $value Field value.
+ * @return \WC_Order
+ */
+ private function create_order_with_field_value( string $value ): \WC_Order {
+ $order = \WC_Helper_Order::create_order();
+ $order->set_created_via( 'store-api' );
+ Package::container()->get( CheckoutFields::class )->persist_field_for_order( $this->field_id, $value, $order, 'billing', false );
+ $order->save();
+
+ return $order;
+ }
+
+ /**
+ * Render the billing address block content for the given order with full view permissions.
+ *
+ * @param \WC_Order $order Order object.
+ * @return string
+ */
+ private function render( \WC_Order $order ): string {
+ $proxy = new class() extends BillingAddressBlock {
+ // phpcs:ignore Squiz.Commenting.FunctionComment.Missing
+ public function __construct() {
+ }
+ // phpcs:ignore Squiz.Commenting.FunctionComment.Missing
+ public function render_content_proxy( $order, $permission ) {
+ return $this->render_content( $order, $permission );
+ }
+ };
+
+ return $proxy->render_content_proxy( $order, 'full' );
+ }
+}
diff --git a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/OrderConfirmation/ShippingAddress.php b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/OrderConfirmation/ShippingAddress.php
new file mode 100644
index 00000000000..51df23985eb
--- /dev/null
+++ b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/OrderConfirmation/ShippingAddress.php
@@ -0,0 +1,104 @@
+<?php declare( strict_types = 1 );
+
+namespace Automattic\WooCommerce\Tests\Blocks\BlockTypes\OrderConfirmation;
+
+use Automattic\WooCommerce\Blocks\BlockTypes\OrderConfirmation\ShippingAddress as ShippingAddressBlock;
+use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
+use Automattic\WooCommerce\Blocks\Package;
+
+/**
+ * Test ShippingAddress block class.
+ */
+final class ShippingAddress extends \WP_UnitTestCase {
+ /**
+ * Field id registered for the duration of a test.
+ *
+ * @var string
+ */
+ private $field_id = 'plugin-namespace/shipping-confirmation-field';
+
+ /**
+ * Tear down test fixtures.
+ */
+ public function tear_down() {
+ __internal_woocommerce_blocks_deregister_checkout_field( $this->field_id );
+ parent::tear_down();
+ }
+
+ /**
+ * @testdox Additional address field values with show_in_order_confirmation set to false are hidden from the block.
+ */
+ public function test_hides_field_when_show_in_order_confirmation_is_false(): void {
+ woocommerce_register_additional_checkout_field(
+ array(
+ 'id' => $this->field_id,
+ 'label' => 'Hidden on confirmation',
+ 'location' => 'address',
+ 'show_in_order_confirmation' => false,
+ )
+ );
+
+ $order = $this->create_order_with_field_value( 'secret value' );
+
+ $this->assertStringNotContainsString( 'secret value', $this->render( $order ) );
+ }
+
+ /**
+ * @testdox Additional address field values with show_in_order_confirmation set to true (the default) are shown in the block.
+ */
+ public function test_shows_field_when_show_in_order_confirmation_is_true(): void {
+ woocommerce_register_additional_checkout_field(
+ array(
+ 'id' => $this->field_id,
+ 'label' => 'Shown on confirmation',
+ 'location' => 'address',
+ )
+ );
+
+ $order = $this->create_order_with_field_value( 'visible value' );
+
+ $this->assertStringContainsString( 'visible value', $this->render( $order ) );
+ }
+
+ /**
+ * Create an order placed via the Store API, with a shipping address and a value persisted for the shipping group of the test field.
+ *
+ * @param string $value Field value.
+ * @return \WC_Order
+ */
+ private function create_order_with_field_value( string $value ): \WC_Order {
+ $order = \WC_Helper_Order::create_order();
+ $order->set_created_via( 'store-api' );
+ $order->set_shipping_first_name( 'Jeroen' );
+ $order->set_shipping_last_name( 'Sormani' );
+ $order->set_shipping_address_1( 'WooAddress' );
+ $order->set_shipping_city( 'WooCity' );
+ $order->set_shipping_state( 'NY' );
+ $order->set_shipping_postcode( '12345' );
+ $order->set_shipping_country( 'US' );
+ Package::container()->get( CheckoutFields::class )->persist_field_for_order( $this->field_id, $value, $order, 'shipping', false );
+ $order->save();
+
+ return $order;
+ }
+
+ /**
+ * Render the shipping address block content for the given order with full view permissions.
+ *
+ * @param \WC_Order $order Order object.
+ * @return string
+ */
+ private function render( \WC_Order $order ): string {
+ $proxy = new class() extends ShippingAddressBlock {
+ // phpcs:ignore Squiz.Commenting.FunctionComment.Missing
+ public function __construct() {
+ }
+ // phpcs:ignore Squiz.Commenting.FunctionComment.Missing
+ public function render_content_proxy( $order, $permission ) {
+ return $this->render_content( $order, $permission );
+ }
+ };
+
+ return $proxy->render_content_proxy( $order, 'full' );
+ }
+}
diff --git a/plugins/woocommerce/tests/php/src/Blocks/Domain/Services/CheckoutFieldsFrontendTest.php b/plugins/woocommerce/tests/php/src/Blocks/Domain/Services/CheckoutFieldsFrontendTest.php
index 182af90b9b7..e4f2ad93611 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/Domain/Services/CheckoutFieldsFrontendTest.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/Domain/Services/CheckoutFieldsFrontendTest.php
@@ -29,6 +29,13 @@ class CheckoutFieldsFrontendTest extends TestCase {
*/
private $controller;
+ /**
+ * Field IDs registered during a test, to be deregistered in tearDown.
+ *
+ * @var string[]
+ */
+ private $registered_fields = [];
+
/**
* Setup.
*/
@@ -50,6 +57,21 @@ class CheckoutFieldsFrontendTest extends TestCase {
remove_filter( 'woocommerce_add_notice', [ $this, 'capture_notice' ] );
remove_filter( 'woocommerce_add_error', [ $this, 'capture_error' ] );
remove_filter( 'woocommerce_add_success', [ $this, 'capture_success' ] );
+
+ foreach ( $this->registered_fields as $field_id ) {
+ __internal_woocommerce_blocks_deregister_checkout_field( $field_id );
+ }
+ $this->registered_fields = [];
+ }
+
+ /**
+ * Register a checkout field and track it for cleanup in tearDown.
+ *
+ * @param array $args Field registration arguments.
+ */
+ private function register_checkout_field( array $args ): void {
+ woocommerce_register_additional_checkout_field( $args );
+ $this->registered_fields[] = $args['id'];
}
/**
@@ -124,7 +146,7 @@ class CheckoutFieldsFrontendTest extends TestCase {
*/
public function test_save_account_form_fields_contact_generic_validation_error() {
- woocommerce_register_additional_checkout_field(
+ $this->register_checkout_field(
array(
'id' => 'mynamespace/generic_validation_error',
'label' => 'Optional field with validation',
@@ -161,8 +183,6 @@ class CheckoutFieldsFrontendTest extends TestCase {
$value = $this->controller->get_field_from_object( 'mynamespace/generic_validation_error', new WC_Customer( 1 ) );
$this->assertEquals( '', $value );
-
- __internal_woocommerce_blocks_deregister_checkout_field( 'mynamespace/generic_validation_error' );
}
/**
@@ -170,7 +190,7 @@ class CheckoutFieldsFrontendTest extends TestCase {
*/
public function test_save_account_form_fields_contact_location_validation_error() {
- woocommerce_register_additional_checkout_field(
+ $this->register_checkout_field(
array(
'id' => 'mynamespace/location_validation_error',
'label' => 'Impossible contact field',
@@ -197,8 +217,6 @@ class CheckoutFieldsFrontendTest extends TestCase {
$value = $this->controller->get_field_from_object( 'mynamespace/required_field', new WC_Customer( 1 ) );
$this->assertEquals( '', $value );
- __internal_woocommerce_blocks_deregister_checkout_field( 'mynamespace/location_validation_error' );
-
remove_action( 'woocommerce_blocks_validate_location_contact_fields', $e_thrower );
}
@@ -207,7 +225,7 @@ class CheckoutFieldsFrontendTest extends TestCase {
*/
public function test_save_account_form_fields_contact_save_required_field() {
- woocommerce_register_additional_checkout_field(
+ $this->register_checkout_field(
array(
'id' => 'mynamespace/required_field',
'label' => 'Required field',
@@ -238,8 +256,6 @@ class CheckoutFieldsFrontendTest extends TestCase {
$value = $this->controller->get_field_from_object( 'mynamespace/required_field', new WC_Customer( 1 ) );
$this->assertEquals( $hash, $value );
-
- __internal_woocommerce_blocks_deregister_checkout_field( 'mynamespace/required_field' );
}
/**
@@ -247,7 +263,7 @@ class CheckoutFieldsFrontendTest extends TestCase {
*/
public function test_save_account_form_fields_contact_save_optional_field() {
- woocommerce_register_additional_checkout_field(
+ $this->register_checkout_field(
array(
'id' => 'mynamespace/optional_field',
'label' => 'Optional field',
@@ -275,15 +291,13 @@ class CheckoutFieldsFrontendTest extends TestCase {
$value = $this->controller->get_field_from_object( 'mynamespace/optional_field', new WC_Customer( 1 ) );
$this->assertEquals( $hash, $value );
-
- __internal_woocommerce_blocks_deregister_checkout_field( 'mynamespace/optional_field' );
}
/**
* @testDox Contact additional field validation error for an optional email field to ensure validation rules are applied.
*/
public function test_save_account_form_fields_contact_email_validation_error_optional_field() {
- woocommerce_register_additional_checkout_field(
+ $this->register_checkout_field(
array(
'id' => 'mynamespace/email_validation_error',
'label' => 'Optional field with validation',
@@ -325,15 +339,13 @@ class CheckoutFieldsFrontendTest extends TestCase {
$value = $this->controller->get_field_from_object( 'mynamespace/email_validation_error', new WC_Customer( 1 ) );
$this->assertEquals( '', $value );
-
- __internal_woocommerce_blocks_deregister_checkout_field( 'mynamespace/email_validation_error' );
}
/**
* @testDox Optional field with existing value can be cleared by submitting empty value.
*/
public function test_save_account_form_fields_optional_field_can_be_cleared() {
- woocommerce_register_additional_checkout_field(
+ $this->register_checkout_field(
array(
'id' => 'mynamespace/optional_field',
'label' => 'Optional field',
@@ -355,7 +367,54 @@ class CheckoutFieldsFrontendTest extends TestCase {
$value = $this->controller->get_field_from_object( 'mynamespace/optional_field', new WC_Customer( 1 ) );
$this->assertEquals( '', $value );
+ }
+
+ /**
+ * @testDox Additional address field values with show_in_order_confirmation set to false are hidden when rendering order details.
+ */
+ public function test_render_order_address_fields_hides_field_when_show_in_order_confirmation_is_false() {
+ $this->register_checkout_field(
+ array(
+ 'id' => 'mynamespace/billing_confirmation_field',
+ 'label' => 'Hidden on confirmation',
+ 'location' => 'address',
+ 'show_in_order_confirmation' => false,
+ )
+ );
+
+ $order = \WC_Helper_Order::create_order();
+ $order->set_created_via( 'store-api' );
+ $this->controller->persist_field_for_order( 'mynamespace/billing_confirmation_field', 'secret value', $order, 'billing', false );
+ $order->save();
+
+ ob_start();
+ $this->sut->render_order_address_fields( 'billing', $order );
+ $content = ob_get_clean();
+
+ $this->assertStringNotContainsString( 'secret value', $content );
+ }
+
+ /**
+ * @testDox Additional address field values with show_in_order_confirmation set to true (the default) are shown when rendering order details.
+ */
+ public function test_render_order_address_fields_shows_field_when_show_in_order_confirmation_is_true() {
+ $this->register_checkout_field(
+ array(
+ 'id' => 'mynamespace/billing_confirmation_field',
+ 'label' => 'Shown on confirmation',
+ 'location' => 'address',
+ )
+ );
+
+ $order = \WC_Helper_Order::create_order();
+ $order->set_created_via( 'store-api' );
+ $this->controller->persist_field_for_order( 'mynamespace/billing_confirmation_field', 'visible value', $order, 'billing', false );
+ $order->save();
+
+ ob_start();
+ $this->sut->render_order_address_fields( 'billing', $order );
+ $content = ob_get_clean();
- __internal_woocommerce_blocks_deregister_checkout_field( 'mynamespace/optional_field' );
+ $this->assertStringContainsString( 'visible value', $content );
}
}