Commit 1899f3f1c4a for woocommerce

commit 1899f3f1c4aa9d7b57f6105e612de1205c47556b
Author: Edith Allison <edith@agentur-allison.at>
Date:   Fri Sep 18 13:14:54 2026 +0200

    fix issue 36095 missing array key (#36437)

    * fix issue 36095 missing array key

    * Preserve customer filter value for guest orders

    * Add customer filter regression coverage

    * Document customer filter result shape

    * Remove resolved PHPDoc error from PHPStan baseline

    ---------

    Co-authored-by: Thomas Roberts <5656702+opr@users.noreply.github.com>

diff --git a/plugins/woocommerce/changelog/fix-36095-customer-filter-key b/plugins/woocommerce/changelog/fix-36095-customer-filter-key
new file mode 100644
index 00000000000..de7e32d6f9c
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-36095-customer-filter-key
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Preserve customer IDs in the `woocommerce_json_search_found_customers` filter on order edit screens.
diff --git a/plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-order-data.php b/plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-order-data.php
index cff5338a7b7..63d5e4d7c5a 100644
--- a/plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-order-data.php
+++ b/plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-order-data.php
@@ -464,7 +464,7 @@ class WC_Meta_Box_Order_Data {
 								?>
 							</label>
 							<?php
-							$user_string = '';
+							$found_users = array( '' );
 							$user_id     = '';
 							if ( $order->get_user_id() ) {
 								$user_id = absint( $order->get_user_id() );
@@ -473,16 +473,18 @@ class WC_Meta_Box_Order_Data {
 								if ( ! is_wp_error( $user ) ) {
 									$customer = new WC_Customer( $user_id );
 									/* translators: 1: user display name 2: user ID 3: user email */
-									$user_string = sprintf(
-									/* translators: 1: customer name, 2 customer id, 3: customer email */
-										esc_html__( '%1$s (#%2$s &ndash; %3$s)', 'woocommerce' ),
-										$customer->get_first_name() . ' ' . $customer->get_last_name(),
-										$customer->get_id(),
-										$customer->get_email()
+									$found_users = array(
+										$user_id => sprintf(
+											/* translators: 1: customer name, 2 customer id, 3: customer email */
+											esc_html__( '%1$s (#%2$s &ndash; %3$s)', 'woocommerce' ),
+											$customer->get_first_name() . ' ' . $customer->get_last_name(),
+											$customer->get_id(),
+											$customer->get_email()
+										),
 									);
 								} else {
 									// print customer not available in the current site.
-									$user_string = esc_html__( '(Not available)', 'woocommerce' );
+									$found_users = array( $user_id => esc_html__( '(Not available)', 'woocommerce' ) );
 								}
 							}
 							?>
@@ -495,10 +497,11 @@ class WC_Meta_Box_Order_Data {
 								 *
 								 * @since 7.2.0 (this instance of the filter)
 								 *
-								 * @param array @user_info An array containing one item with the name and email of the user currently selected as the customer for the order.
+								 * @param array $found_users An array containing the selected customer label keyed by user ID.
+								 *                           Guest orders contain a single empty string with numeric key 0.
 								 */
 								?>
-								<option value="<?php echo esc_attr( $user_id ); ?>" selected="selected"><?php echo esc_html( htmlspecialchars( wp_kses_post( current( apply_filters( 'woocommerce_json_search_found_customers', array( $user_string ) ) ) ) ) ); ?></option>
+								<option value="<?php echo esc_attr( $user_id ); ?>" selected="selected"><?php echo esc_html( htmlspecialchars( wp_kses_post( current( apply_filters( 'woocommerce_json_search_found_customers', $found_users ) ) ), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ) ); ?></option>
 								<?php // phpcs:enable WooCommerce.Commenting.CommentHooks.MissingHookComment ?>
 							</select>
 							<!--/email_off-->
diff --git a/plugins/woocommerce/phpstan-baseline.neon b/plugins/woocommerce/phpstan-baseline.neon
index 11cc1713ef3..85d7650ad9f 100644
--- a/plugins/woocommerce/phpstan-baseline.neon
+++ b/plugins/woocommerce/phpstan-baseline.neon
@@ -5328,12 +5328,6 @@ parameters:
 			count: 5
 			path: includes/admin/meta-boxes/class-wc-meta-box-order-data.php

-		-
-			message: '#^PHPDoc tag @param has invalid value \(array @user_info An array containing one item with the name and email of the user currently selected as the customer for the order\.\)\: Unexpected token "@user", expected variable at offset 317 on line 7$#'
-			identifier: phpDoc.parseError
-			count: 1
-			path: includes/admin/meta-boxes/class-wc-meta-box-order-data.php
-
 		-
 			message: '#^PHPDoc tag @param has invalid value \(array Billing fields\.\)\: Unexpected token "Billing", expected variable at offset 146 on line 6$#'
 			identifier: phpDoc.parseError
diff --git a/plugins/woocommerce/tests/php/includes/admin/meta-boxes/class-wc-meta-box-order-data-test.php b/plugins/woocommerce/tests/php/includes/admin/meta-boxes/class-wc-meta-box-order-data-test.php
index 858d1ce2755..753caceb029 100644
--- a/plugins/woocommerce/tests/php/includes/admin/meta-boxes/class-wc-meta-box-order-data-test.php
+++ b/plugins/woocommerce/tests/php/includes/admin/meta-boxes/class-wc-meta-box-order-data-test.php
@@ -109,6 +109,50 @@ class WC_Meta_Box_Order_Data_Test extends WC_Unit_Test_Case {
 		parent::tearDown();
 	}

+	/**
+	 * @testdox The customer filter receives keyed registered customers and the legacy guest value.
+	 */
+	public function test_customer_filter_receives_expected_customer_shapes(): void {
+		$customer = WC_Helper_Customer::create_customer( 'order_data_customer', 'password', 'order-data-customer@example.com' );
+		$customer->set_first_name( 'Order Data' );
+		$customer->set_last_name( 'Customer' );
+		$customer->save();
+
+		$registered_order = wc_create_order( array( 'customer_id' => $customer->get_id() ) );
+		$guest_order      = wc_create_order( array( 'customer_id' => 0 ) );
+		$this->orders[]   = $registered_order;
+		$this->orders[]   = $guest_order;
+
+		$filter_inputs     = array();
+		$customer_filter   = static function ( $found_users ) use ( &$filter_inputs ) {
+			$filter_inputs[] = $found_users;
+
+			return array( array( '' ) === $found_users ? 'Filtered guest customer' : 'Filtered registered customer' );
+		};
+		$render_order_data = static function ( WC_Order $order ): string {
+			$GLOBALS['theorder'] = null;
+
+			ob_start();
+			WC_Meta_Box_Order_Data::output( $order );
+
+			return (string) ob_get_clean();
+		};
+		add_filter( 'woocommerce_json_search_found_customers', $customer_filter );
+
+		try {
+			$registered_output = $render_order_data( $registered_order );
+			$guest_output      = $render_order_data( $guest_order );
+		} finally {
+			remove_filter( 'woocommerce_json_search_found_customers', $customer_filter );
+		}
+
+		$this->assertCount( 2, $filter_inputs, 'The filter should run once for each rendered order.' );
+		$this->assertSame( array( $customer->get_id() ), array_keys( $filter_inputs[0] ), 'The registered customer should be keyed by user ID.' );
+		$this->assertSame( array( '' ), $filter_inputs[1], 'Guest orders should retain the legacy filter value.' );
+		$this->assertStringContainsString( '>Filtered registered customer</option>', $registered_output );
+		$this->assertStringContainsString( '>Filtered guest customer</option>', $guest_output );
+	}
+
 	/**
 	 * @testdox The read-only summary hides persisted shipping details when the order does not need shipping.
 	 */