Commit 77d725ae012 for woocommerce

commit 77d725ae01255aa1b20d07e432be64ce60f9ce7f
Author: Néstor Soriano <konamiman@konamiman.com>
Date:   Thu Aug 6 05:21:38 2026 +0900

    Fix emptied customer address fields being restored from saved values (#65703)

    * Fix emptied customer address fields being restored from saved values

    * Remove redundant test and changelog file

    * Add changelog entry for the customer session data store tests

    ---------

    Co-authored-by: Brandon Kraft <public@brandonkraft.com>

diff --git a/plugins/woocommerce/changelog/65703-add-customer-session-empty-value-tests b/plugins/woocommerce/changelog/65703-add-customer-session-empty-value-tests
new file mode 100644
index 00000000000..bbe4d310865
--- /dev/null
+++ b/plugins/woocommerce/changelog/65703-add-customer-session-empty-value-tests
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+
+Add unit tests covering empty customer session values overriding persisted customer data.
diff --git a/plugins/woocommerce/includes/data-stores/class-wc-customer-data-store-session.php b/plugins/woocommerce/includes/data-stores/class-wc-customer-data-store-session.php
index e6ab8928453..f6fd37974d7 100644
--- a/plugins/woocommerce/includes/data-stores/class-wc-customer-data-store-session.php
+++ b/plugins/woocommerce/includes/data-stores/class-wc-customer-data-store-session.php
@@ -111,6 +111,9 @@ class WC_Customer_Data_Store_Session extends WC_Data_Store_WP implements WC_Cust
 		 * There is a valid session if $data is not empty, and the ID matches the logged in user ID.
 		 *
 		 * If the user object has been updated since the session was created (based on date_modified) we should not load the session - data should be reloaded.
+		 *
+		 * Empty session values must be applied too (hence isset and not empty below): the session snapshot always contains all the keys,
+		 * so an empty value means the field was explicitly cleared and must override the value loaded from the database.
 		 */
 		if ( isset( $data['id'], $data['date_modified'] ) && $data['id'] === (string) $customer->get_id() && $data['date_modified'] === (string) $customer->get_date_modified( 'edit' ) ) {
 			foreach ( $this->session_keys as $session_key ) {
diff --git a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-customer-data-store-session-test.php b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-customer-data-store-session-test.php
index 7f0b0eec713..f16298dd7b9 100644
--- a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-customer-data-store-session-test.php
+++ b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-customer-data-store-session-test.php
@@ -4,6 +4,24 @@
  * Tests relating to the WC_Customer_Data_Store_Session class.
  */
 class WC_Customer_Data_Store_Session_Test extends WC_Unit_Test_Case {
+
+	/**
+	 * Set up test fixtures.
+	 */
+	public function setUp(): void {
+		parent::setUp();
+		WC()->session->set( 'customer', null );
+	}
+
+	/**
+	 * Tear down test fixtures.
+	 */
+	public function tearDown(): void {
+		WC()->session->set( 'customer', null );
+		wp_set_current_user( 0 );
+		parent::tearDown();
+	}
+
 	/**
 	 * Ensure that the country and state shipping address fields only inherit
 	 * the corresponding billing address values if a shipping address is not set.
@@ -65,6 +83,97 @@ class WC_Customer_Data_Store_Session_Test extends WC_Unit_Test_Case {
 		$this->assertArrayNotHasKey( 'customer', $session_data );
 	}

+	/**
+	 * @testdox Should override a persisted billing field with an empty value stored in the session.
+	 */
+	public function test_empty_session_value_overrides_persisted_billing_field(): void {
+		$customer_id = WC_Helper_Customer::create_customer( 'session_empty_billing', 'password', 'session-empty-billing@example.com' )->get_id();
+
+		$session_customer = new WC_Customer( $customer_id, true );
+		$session_customer->set_billing_address_2( '' );
+		$session_customer->save();
+
+		$reloaded_customer = new WC_Customer( $customer_id, true );
+
+		$this->assertSame( '', $reloaded_customer->get_billing_address_2(), 'A billing field emptied in the session should not be restored from the persisted customer data' );
+	}
+
+	/**
+	 * @testdox Should leave persisted values untouched for keys that are absent from the session data.
+	 */
+	public function test_keys_absent_from_session_data_keep_persisted_values(): void {
+		$customer_id   = WC_Helper_Customer::create_customer( 'session_absent_keys', 'password', 'session-absent-keys@example.com' )->get_id();
+		$date_modified = (string) ( new WC_Customer( $customer_id ) )->get_date_modified( 'edit' );
+
+		WC()->session->set(
+			'customer',
+			array(
+				'id'            => (string) $customer_id,
+				'date_modified' => $date_modified,
+				'first_name'    => 'Session-Name',
+			)
+		);
+
+		$customer = new WC_Customer( $customer_id, true );
+
+		$this->assertSame( 'Session-Name', $customer->get_billing_first_name(), 'Keys present in the session data should be applied' );
+		$this->assertSame( 'Apt 1', $customer->get_shipping_address_2(), 'Keys absent from the session data should keep the persisted values' );
+	}
+
+	/**
+	 * @testdox Should ignore the session data entirely when the date modified does not match the persisted customer.
+	 */
+	public function test_stale_session_data_is_ignored(): void {
+		$customer_id = WC_Helper_Customer::create_customer( 'session_stale_data', 'password', 'session-stale-data@example.com' )->get_id();
+
+		WC()->session->set(
+			'customer',
+			array(
+				'id'                 => (string) $customer_id,
+				'date_modified'      => 'stale-date',
+				'address_2'          => '',
+				'shipping_address_2' => '',
+			)
+		);
+
+		$customer = new WC_Customer( $customer_id, true );
+
+		$this->assertSame( 'Apt 1', $customer->get_billing_address_2(), 'Stale session data should not override the persisted billing values' );
+		$this->assertSame( 'Apt 1', $customer->get_shipping_address_2(), 'Stale session data should not override the persisted shipping values' );
+	}
+
+	/**
+	 * @testdox Should fall back to the default location when the billing country is emptied in the session.
+	 */
+	public function test_emptied_billing_country_falls_back_to_default_location(): void {
+		$customer_id = WC_Helper_Customer::create_customer( 'session_empty_country', 'password', 'session-empty-country@example.com' )->get_id();
+
+		$session_customer = new WC_Customer( $customer_id, true );
+		$session_customer->set_billing_country( '' );
+		$session_customer->save();
+
+		$reloaded_customer = new WC_Customer( $customer_id, true );
+		$default_location  = wc_get_customer_default_location();
+
+		$this->assertSame( $default_location['country'], $reloaded_customer->get_billing_country(), 'An emptied billing country should be replaced with the default location country' );
+	}
+
+	/**
+	 * @testdox Should fall back to the account email when the billing email is emptied in the session for a logged in user.
+	 */
+	public function test_emptied_billing_email_falls_back_to_account_email_for_logged_in_user(): void {
+		$customer_id = WC_Helper_Customer::create_customer( 'session_empty_email', 'password', 'session-empty-email@example.com' )->get_id();
+		wp_set_current_user( $customer_id );
+
+		$session_customer = new WC_Customer( $customer_id, true );
+		$session_customer->set_billing_email( '' );
+		$session_customer->save();
+
+		$reloaded_customer = new WC_Customer( $customer_id, true );
+
+		$this->assertSame( 'session-empty-email@example.com', $reloaded_customer->get_billing_email(), 'An emptied billing email should be replaced with the account email for logged in users' );
+	}
+
 	/**
 	 * Customer objects with a mixture of billing and shipping addresses.
 	 *