Commit 6c5bc3d514 for woocommerce

commit 6c5bc3d514c1b3befc73349db9339c5299be3cd8
Author: Albert Juhé Lluveras <contact@albertjuhe.com>
Date:   Mon Jun 16 17:48:05 2025 +0200

    Add missing classes used by some express payment methods to the Add to Cart + Options block (#58809)

    * Add missing classes used by some express payment methods to the Add to Cart + Options block

    * Add changelog file

    * Fix PAO

    * Remove unnecessary class for simple products

    * Escape

diff --git a/plugins/woocommerce/changelog/fix-58806-add-to-cart-with-options-express-payment-methods-classes b/plugins/woocommerce/changelog/fix-58806-add-to-cart-with-options-express-payment-methods-classes
new file mode 100644
index 0000000000..3c03ba2a7c
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-58806-add-to-cart-with-options-express-payment-methods-classes
@@ -0,0 +1,5 @@
+Significance: patch
+Type: fix
+Comment: Add missing classes used by some express payment methods to the Add to Cart + Options block
+
+
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/AddToCartWithOptions.php b/plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/AddToCartWithOptions.php
index c959583375..aa915086ff 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/AddToCartWithOptions.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/AddToCartWithOptions/AddToCartWithOptions.php
@@ -111,14 +111,14 @@ class AddToCartWithOptions extends AbstractBlock {
 	protected function render( $attributes, $content, $block ) {
 		global $product;

-		$post_id = $block->context['postId'];
+		$product_id = $block->context['postId'];

-		if ( ! isset( $post_id ) ) {
+		if ( ! isset( $product_id ) ) {
 			return '';
 		}

 		$previous_product = $product;
-		$product          = wc_get_product( $post_id );
+		$product          = wc_get_product( $product_id );
 		if ( ! $product instanceof \WC_Product ) {
 			$product = $previous_product;

@@ -426,7 +426,6 @@ class AddToCartWithOptions extends AbstractBlock {

 			$cart_redirect_after_add = get_option( 'woocommerce_cart_redirect_after_add' );
 			$form_attributes         = '';
-			$hidden_input            = '';
 			$legacy_mode             = $hooks_before || $hooks_after || 'yes' === $cart_redirect_after_add;
 			if ( $legacy_mode ) {
 				// If an extension is hoooking into the form or we need to redirect to the cart,
@@ -446,15 +445,6 @@ class AddToCartWithOptions extends AbstractBlock {
 					'enctype' => 'multipart/form-data',
 					'class'   => 'cart',
 				);
-				if ( ProductType::SIMPLE === $product_type ) {
-					$hidden_input = '<input type="hidden" name="add-to-cart" value="' . $product->get_id() . '" />';
-				} elseif ( ProductType::GROUPED === $product_type ) {
-					$hidden_input = '<input type="hidden" name="add-to-cart" value="' . $product->get_id() . '" />';
-				} elseif ( ProductType::VARIABLE === $product_type ) {
-					$hidden_input  = '<input type="hidden" name="add-to-cart" value="' . $product->get_id() . '" />';
-					$hidden_input .= '<input type="hidden" name="product_id" value="' . $product->get_id() . '" />';
-					$hidden_input .= '<input type="hidden" name="variation_id" data-wp-interactive="woocommerce/add-to-cart-with-options" data-wp-bind--value="state.variationId" />';
-				}
 			} else {
 				// Otherwise, we use the Interactivity API.
 				$form_attributes = array(
@@ -462,6 +452,24 @@ class AddToCartWithOptions extends AbstractBlock {
 				);
 			}

+			// These hidden inputs are used by extensions or Express Payment methods to gather information of the form state.
+			$hidden_input = '';
+			if ( ProductType::SIMPLE === $product_type ) {
+				$hidden_input = '<input type="hidden" name="add-to-cart" value="' . esc_attr( $product_id ) . '" />';
+			} elseif ( ProductType::GROUPED === $product_type ) {
+				$hidden_input = '<input type="hidden" name="add-to-cart" value="' . esc_attr( $product_id ) . '" />';
+			} elseif ( ProductType::VARIABLE === $product_type ) {
+				$hidden_input = '<div class="single_variation_wrap">
+					<input type="hidden" name="add-to-cart" value="' . esc_attr( $product_id ) . '" />
+					<input type="hidden" name="product_id" value="' . esc_attr( $product_id ) . '" />
+					<input type="hidden"
+						name="variation_id"
+						data-wp-interactive="woocommerce/add-to-cart-with-options"
+						data-wp-bind--value="state.variationId"
+					/>
+				</div>';
+			}
+
 			$form_html = sprintf(
 				'<form %1$s>%2$s%3$s%4$s%5$s</form>',
 				get_block_wrapper_attributes(
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductButton.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductButton.php
index 2792161cda..4ca13dcb11 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductButton.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductButton.php
@@ -219,7 +219,9 @@ class ProductButton extends AbstractBlock {
 			data-wp-init="actions.refreshCartItems"
 		';

-		$button_directives = $is_descendant_of_add_to_cart_form ? '' : 'data-wp-on--click="actions.addCartItem"';
+		$button_directives = $is_descendant_of_add_to_cart_form ?
+			'data-wp-class--disabled="woocommerce/add-to-cart-with-options::!state.isFormValid"' :
+			'data-wp-on--click="actions.addCartItem"';
 		$anchor_directive  = $is_descendant_of_add_to_cart_form ? '' : 'data-wp-on--click="woocommerce/product-collection::actions.viewProduct"';

 		$span_button_directives = '
@@ -246,6 +248,12 @@ class ProductButton extends AbstractBlock {
 			)
 		);

+		$button_classes = isset( $args['class'] ) ? esc_attr( $args['class'] . ' wc-interactive' ) : 'wc-interactive';
+		if ( $is_descendant_of_add_to_cart_form ) {
+			$button_classes             .= ' single_add_to_cart_button';
+			$args['attributes']['value'] = $product->get_id();
+		}
+
 		/**
 		 * Filters the add to cart button class.
 		 *
@@ -272,7 +280,7 @@ class ProductButton extends AbstractBlock {
 				array(
 					'{wrapper_attributes}'     => $wrapper_attributes,
 					'{html_element}'           => $html_element,
-					'{button_classes}'         => isset( $args['class'] ) ? esc_attr( $args['class'] . ' wc-interactive' ) : 'wc-interactive',
+					'{button_classes}'         => $button_classes,
 					'{button_styles}'          => esc_attr( $styles_and_classes['styles'] ),
 					'{attributes}'             => isset( $args['attributes'] ) ? wc_implode_html_attributes( $args['attributes'] ) : '',
 					'{add_to_cart_text}'       => $is_ajax_button ? '' : $add_to_cart_text,