Commit b882e149e72 for woocommerce
commit b882e149e724c145fddc248d4fe49520367b56b4
Author: Michal Iwanow <4765119+mcliwanow@users.noreply.github.com>
Date: Wed Nov 4 13:58:33 2026 +0100
Ignore unused variation attributes when adding to the cart (#70633)
The cart keeps only the attributes the parent product uses for variations, and the meta box tab script looks up panels with $( document ).find().
Co-authored-by: Tung Du <5423135+dinhtungdu@users.noreply.github.com>
diff --git a/plugins/woocommerce/changelog/fix-cart-variation-attributes b/plugins/woocommerce/changelog/fix-cart-variation-attributes
new file mode 100644
index 00000000000..c6f997a3d1f
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-cart-variation-attributes
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+When a shopper adds a product to the cart, ignore attributes that the product does not use.
diff --git a/plugins/woocommerce/client/legacy/js/admin/meta-boxes.js b/plugins/woocommerce/client/legacy/js/admin/meta-boxes.js
index 244f5593c4a..6291466912a 100644
--- a/plugins/woocommerce/client/legacy/js/admin/meta-boxes.js
+++ b/plugins/woocommerce/client/legacy/js/admin/meta-boxes.js
@@ -127,7 +127,14 @@ jQuery( function ( $ ) {
$( 'ul.wc-tabs li', panel_wrap ).removeClass( 'active' );
$( this ).parent().addClass( 'active' );
$( 'div.panel', panel_wrap ).hide();
- $( $( this ).attr( 'href' ) ).show( 0, function () {
+ // Look up the panel by the link's selector. A selector that is not valid finds nothing.
+ var panel;
+ try {
+ panel = $( document ).find( $( this ).attr( 'href' ) || '' );
+ } catch ( error ) {
+ panel = $();
+ }
+ panel.show( 0, function () {
$( this ).trigger( 'woocommerce_tab_shown' );
} );
} );
diff --git a/plugins/woocommerce/includes/class-wc-cart.php b/plugins/woocommerce/includes/class-wc-cart.php
index e61e8d60ba4..8332d29a94e 100644
--- a/plugins/woocommerce/includes/class-wc-cart.php
+++ b/plugins/woocommerce/includes/class-wc-cart.php
@@ -1314,9 +1314,10 @@ class WC_Cart extends WC_Legacy_Cart {
} elseif ( '' === $valid_value ) {
$missing_attributes[] = wc_attribute_label( $attribute['name'] );
}
-
- $variation = $attributes;
}
+
+ // Keep only the checked attributes. This also drops posted values when the parent has no variation attributes.
+ $variation = $attributes;
if ( ! empty( $missing_attributes ) ) {
/* translators: %s: Attribute name. */
throw new Exception( sprintf( _n( '%s is a required field', '%s are required fields', count( $missing_attributes ), 'woocommerce' ), wc_format_list_of_items( $missing_attributes ) ) );
diff --git a/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php b/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php
index 3eeb423a6f8..7433577dcc6 100644
--- a/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php
+++ b/plugins/woocommerce/tests/php/includes/class-wc-cart-test.php
@@ -2844,6 +2844,61 @@ class WC_Cart_Test extends \WC_Unit_Test_Case {
$this->assertEquals( $variation['variation_id'], $this->add_to_cart_quantity_filter_args[2] );
}
+ /**
+ * @testdox Adding a variation to the cart keeps only the attributes its parent uses for variations.
+ * @dataProvider parent_variation_attribute_provider
+ *
+ * @param bool $used_for_variations Whether the parent's Color attribute is ticked "Used for variations".
+ * @param array $expected The variation data the cart item should keep.
+ */
+ public function test_add_to_cart_keeps_only_parent_variation_attributes( bool $used_for_variations, array $expected ): void {
+ $attribute = new WC_Product_Attribute();
+ $attribute->set_name( 'Color' );
+ $attribute->set_options( array( 'Red', 'Blue' ) );
+ $attribute->set_variation( true );
+
+ $product = new WC_Product_Variable();
+ $product->set_attributes( array( $attribute ) );
+ $product->save();
+
+ $variation = new WC_Product_Variation();
+ $variation->set_parent_id( $product->get_id() );
+ $variation->set_attributes( array( 'color' => 'Red' ) );
+ $variation->set_regular_price( '10' );
+ $variation->save();
+
+ // Save the parent again with the box ticked or unticked. Unticking it leaves the variation published and for sale.
+ $attribute = clone $attribute;
+ $attribute->set_variation( $used_for_variations );
+ $product->set_attributes( array( $attribute ) );
+ $product->save();
+
+ $cart_item_key = WC()->cart->add_to_cart(
+ $variation->get_id(),
+ 1,
+ 0,
+ array(
+ 'attribute_color' => 'Red',
+ 'attribute_x' => 'not an option of this product',
+ )
+ );
+
+ $this->assertNotFalse( $cart_item_key );
+ $this->assertSame( $expected, WC()->cart->get_cart_item( $cart_item_key )['variation'] );
+ }
+
+ /**
+ * Provides whether the parent uses Color for variations, and the variation data the cart should keep.
+ *
+ * @return array<string, array{bool, array<string, string>}>
+ */
+ public static function parent_variation_attribute_provider(): array {
+ return array(
+ 'parent uses Color for variations' => array( true, array( 'attribute_color' => 'Red' ) ),
+ 'parent uses no attribute for variations' => array( false, array() ),
+ );
+ }
+
/**
* @testdox woocommerce_add_to_cart_quantity filter should receive 0 as variation_id when a simple product is added to cart.
*/