Commit 772b1285c44 for woocommerce

commit 772b1285c44e019c0995592598bf4a52968bd7b1
Author: Tom Cafferkey <tjcafferkey@gmail.com>
Date:   Fri Oct 9 11:39:37 2026 +0100

    Fix cart validation for protected variations (#69590)

    * Fix cart validation for password-protected variations

    * Add changelog entry for protected variation cart fix

diff --git a/plugins/woocommerce/changelog/fix-protected-variation-add-to-cart b/plugins/woocommerce/changelog/fix-protected-variation-add-to-cart
new file mode 100644
index 00000000000..f93302cafb4
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-protected-variation-add-to-cart
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Prevent password-protected variable products from being added to the cart through their variation IDs.
diff --git a/plugins/woocommerce/includes/wc-cart-functions.php b/plugins/woocommerce/includes/wc-cart-functions.php
index a6426533cae..dedd1d234ac 100644
--- a/plugins/woocommerce/includes/wc-cart-functions.php
+++ b/plugins/woocommerce/includes/wc-cart-functions.php
@@ -24,6 +24,13 @@ defined( 'ABSPATH' ) || exit;
  * @return bool
  */
 function wc_protected_product_add_to_cart( $passed, $product_id ) {
+	if ( 'product_variation' === get_post_type( $product_id ) ) {
+		$parent_id = wp_get_post_parent_id( $product_id );
+		if ( $parent_id ) {
+			$product_id = $parent_id;
+		}
+	}
+
 	if ( post_password_required( $product_id ) ) {
 		$passed = false;
 		wc_add_notice( __( 'This product is protected and cannot be purchased.', 'woocommerce' ), 'error' );
diff --git a/plugins/woocommerce/tests/php/includes/wc-cart-functions-test.php b/plugins/woocommerce/tests/php/includes/wc-cart-functions-test.php
index 48ace107efe..32ccc315bed 100644
--- a/plugins/woocommerce/tests/php/includes/wc-cart-functions-test.php
+++ b/plugins/woocommerce/tests/php/includes/wc-cart-functions-test.php
@@ -12,6 +12,58 @@ declare( strict_types = 1 );
  */
 class WC_Cart_Functions_Test extends WC_Unit_Test_Case {

+	/**
+	 * @testdox A password-protected variable product cannot be added by passing its variation ID to cart validation.
+	 */
+	public function test_protected_variation_fails_add_to_cart_validation(): void {
+		$product      = WC_Helper_Product::create_variation_product();
+		$variation_id = $product->get_children()[0];
+		wp_update_post(
+			array(
+				'ID'            => $product->get_id(),
+				'post_password' => 'secret',
+			)
+		);
+
+		$this->assertFalse( apply_filters( 'woocommerce_add_to_cart_validation', true, $variation_id, 1 ), 'A variation must inherit its parent password protection.' );
+		$this->assertSame( 1, wc_notice_count( 'error' ), 'The rejected variation should display the protected-product notice.' );
+	}
+
+	/**
+	 * @testdox The legacy add-to-cart form rejects a protected product submitted by variation ID.
+	 */
+	public function test_form_rejects_protected_variation_id(): void {
+		$product      = WC_Helper_Product::create_variation_product();
+		$variation_id = $product->get_children()[0];
+		wp_update_post(
+			array(
+				'ID'            => $product->get_id(),
+				'post_password' => 'secret',
+			)
+		);
+
+		$request = $_REQUEST; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Preserve the request so the form test can restore it.
+		try {
+			$_REQUEST['add-to-cart'] = (string) $variation_id; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- The legacy add-to-cart form accepts requests without a nonce.
+			WC_Form_Handler::add_to_cart_action();
+
+			$this->assertCount( 0, WC()->cart->get_cart(), 'The protected variation should not be added to the cart.' );
+			$this->assertSame( 1, wc_notice_count( 'error' ), 'The form should display the protected-product notice.' );
+		} finally {
+			$_REQUEST = $request;
+		}
+	}
+
+	/**
+	 * @testdox An unprotected variation passes add-to-cart validation.
+	 */
+	public function test_unprotected_variation_passes_add_to_cart_validation(): void {
+		$product      = WC_Helper_Product::create_variation_product();
+		$variation_id = $product->get_children()[0];
+
+		$this->assertTrue( apply_filters( 'woocommerce_add_to_cart_validation', true, $variation_id, 1 ), 'An unprotected variation should remain purchasable.' );
+	}
+
 	/**
 	 * @testdox Coupon totals pass the discount to wc_price as a negative amount.
 	 */