Commit cc1e0ab8d18 for woocommerce

commit cc1e0ab8d18a95f6657bdcf183789bece069e0fa
Author: Karol Manijak <20098064+kmanijak@users.noreply.github.com>
Date:   Fri Jul 24 15:56:19 2026 +0200

    Revert "Remove stale variation attribute meta on updates" (#66975)

    Revert "Remove stale variation attribute meta on updates (#65766)"

    This reverts commit 79c1eba3fefe1df2a1e985c47189f5f6fe61acce.

diff --git a/plugins/woocommerce/includes/class-wc-post-data.php b/plugins/woocommerce/includes/class-wc-post-data.php
index 6a856dac094..5359505289b 100644
--- a/plugins/woocommerce/includes/class-wc-post-data.php
+++ b/plugins/woocommerce/includes/class-wc-post-data.php
@@ -12,7 +12,6 @@ use Automattic\WooCommerce\Enums\OrderStatus;
 use Automattic\WooCommerce\Enums\OrderInternalStatus;
 use Automattic\WooCommerce\Enums\ProductStatus;
 use Automattic\WooCommerce\Enums\ProductType;
-use Automattic\WooCommerce\Internal\Caches\ProductVersionStringInvalidator;
 use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer;
 use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore as ProductAttributesLookupDataStore;
 use Automattic\WooCommerce\Proxies\LegacyProxy;
@@ -80,7 +79,7 @@ class WC_Post_Data {
 		add_action( 'edited_term', array( __CLASS__, 'handle_attribute_term_updated' ), 10, 3 );
 		add_action( 'delete_term', array( __CLASS__, 'handle_attribute_term_deleted' ), 10, 4 );
 		// Product Variations - Parent Product Updates Attributes.
-		add_action( 'woocommerce_product_attributes_updated', array( __CLASS__, 'on_product_attributes_updated' ), 10, 2 );
+		add_action( 'woocommerce_product_attributes_updated', array( __CLASS__, 'on_product_attributes_updated' ), 10, 1 );
 		// Product Variations - Action Scheduler.
 		add_action( 'wc_regenerate_product_variation_summaries', array( __CLASS__, 'regenerate_product_variation_summaries' ), 10, 1 );
 		add_action( 'wc_regenerate_attribute_variation_summaries', array( __CLASS__, 'regenerate_attribute_variation_summaries' ), 10, 1 );
@@ -964,19 +963,11 @@ class WC_Post_Data {
 	 *
 	 * @since 10.2.0
 	 * @param WC_Product $product The variable product whose attributes were updated.
-	 * @param bool       $force   Whether the update was forced. Forced updates originate from the read-time
-	 *                            backwards-compatibility migration in the data store, where the product's
-	 *                            in-memory attributes can be an incomplete view of what's stored, so stale
-	 *                            attribute meta cleanup must be skipped to avoid deleting valid meta.
 	 *
 	 * @return void
 	 */
-	public static function on_product_attributes_updated( $product, $force = false ) {
+	public static function on_product_attributes_updated( $product ) {
 		if ( $product->is_type( 'variable' ) ) {
-			if ( ! $force ) {
-				self::delete_stale_variation_attribute_meta( $product );
-			}
-
 			global $wpdb;
 			$threshold     = self::get_variation_summaries_sync_threshold();
 			$variation_ids = $wpdb->get_col(
@@ -1011,71 +1002,6 @@ class WC_Post_Data {
 		}
 	}

-	/**
-	 * Deletes child variation attribute meta that no longer maps to a parent variation attribute.
-	 *
-	 * @param WC_Product $product The variable product whose attributes were updated.
-	 *
-	 * @return void
-	 */
-	private static function delete_stale_variation_attribute_meta( $product ) {
-		global $wpdb;
-
-		$valid_attribute_meta_keys = array();
-		foreach ( $product->get_attributes() as $attribute ) {
-			if ( ! $attribute instanceof WC_Product_Attribute || ! $attribute->get_variation() ) {
-				continue;
-			}
-
-			$valid_attribute_meta_keys[] = wc_variation_attribute_name( $attribute->get_name() );
-		}
-		$valid_attribute_meta_keys = array_values( array_unique( $valid_attribute_meta_keys ) );
-
-		$query_args = array(
-			$product->get_id(),
-			'product_variation',
-			$wpdb->esc_like( 'attribute_' ) . '%',
-		);
-		$not_in_sql = '';
-		if ( ! empty( $valid_attribute_meta_keys ) ) {
-			$not_in_sql = ' AND pm.meta_key NOT IN ( ' . implode( ', ', array_fill( 0, count( $valid_attribute_meta_keys ), '%s' ) ) . ' )';
-			$query_args = array_merge( $query_args, $valid_attribute_meta_keys );
-		}
-
-		// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
-		$stale_rows = $wpdb->get_results(
-			$wpdb->prepare(
-				"SELECT pm.post_id, pm.meta_key
-					FROM {$wpdb->postmeta} pm
-					INNER JOIN {$wpdb->posts} p ON pm.post_id = p.ID
-					WHERE p.post_parent = %d
-				AND p.post_type = %s
-				AND pm.meta_key LIKE %s
-				{$not_in_sql}",
-				...$query_args
-			)
-		);
-
-		if ( empty( $stale_rows ) ) {
-			return;
-		}
-
-		// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
-		$variation_ids = array();
-		foreach ( $stale_rows as $row ) {
-			$variation_id                   = (int) $row->post_id;
-			$variation_ids[ $variation_id ] = $variation_id;
-			delete_post_meta( $variation_id, $row->meta_key );
-		}
-
-		$invalidator = wc_get_container()->get( ProductVersionStringInvalidator::class );
-		foreach ( $variation_ids as $variation_id ) {
-			clean_post_cache( $variation_id );
-			$invalidator->invalidate( $variation_id );
-		}
-		$invalidator->invalidate( $product->get_id() );
-	}
-
 	/**
 	 * Regenerates variation summaries for all variations of a variable product.
 	 *
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-post-data-test.php b/plugins/woocommerce/tests/php/includes/class-wc-post-data-test.php
index 82c1c5c8476..1c9ba3227b7 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-post-data-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-post-data-test.php
@@ -252,45 +252,4 @@ class WC_Post_Data_Test extends \WC_Unit_Test_Case {
 		$this->assertSame( array( $product_1->get_id(), $product_2->get_id() ), $synced_ids, 'Each product should be synced at most once per request' );
 		$this->assertEmpty( $wc_deferred_product_sync, 'The queue should be empty after the sync' );
 	}
-
-	/**
-	 * @testdox Should delete variation attribute meta when the parent variation attribute is removed.
-	 */
-	public function test_product_attributes_updated_deletes_stale_variation_attribute_meta(): void {
-		$product       = WC_Helper_Product::create_variation_product();
-		$variation_ids = $product->get_children();
-
-		foreach ( $variation_ids as $variation_id ) {
-			update_post_meta( $variation_id, 'attribute_pa_colour', 'red' );
-			$this->assertSame( 'red', get_post_meta( $variation_id, 'attribute_pa_colour', true ), 'Variation should start with colour attribute meta' );
-		}
-
-		$attributes = $product->get_attributes();
-		unset( $attributes['pa_colour'] );
-		$product->set_attributes( $attributes );
-		$product->save();
-
-		foreach ( $variation_ids as $variation_id ) {
-			$this->assertFalse( metadata_exists( 'post', $variation_id, 'attribute_pa_colour' ), 'Removed parent variation attribute meta should be deleted from each child variation' );
-		}
-		$this->assertSame( 'huge', get_post_meta( $variation_ids[2], 'attribute_pa_size', true ), 'Remaining parent variation attribute meta should be preserved' );
-
-		$product       = WC_Helper_Product::create_variation_product();
-		$variation_ids = $product->get_children();
-
-		foreach ( $variation_ids as $variation_id ) {
-			update_post_meta( $variation_id, 'attribute_pa_size', 'huge' );
-			update_post_meta( $variation_id, 'attribute_pa_colour', 'red' );
-			update_post_meta( $variation_id, 'attribute_pa_number', '2' );
-		}
-
-		$product->set_attributes( array() );
-		$product->save();
-
-		foreach ( $variation_ids as $variation_id ) {
-			$this->assertFalse( metadata_exists( 'post', $variation_id, 'attribute_pa_size' ), 'Removed size attribute meta should be deleted from each child variation' );
-			$this->assertFalse( metadata_exists( 'post', $variation_id, 'attribute_pa_colour' ), 'Removed colour attribute meta should be deleted from each child variation' );
-			$this->assertFalse( metadata_exists( 'post', $variation_id, 'attribute_pa_number' ), 'Removed number attribute meta should be deleted from each child variation' );
-		}
-	}
 }