From 379a2e718914a77cc69121fcfc69c79ebc623f09 Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Wed, 17 May 2023 14:06:04 +0200 Subject: [PATCH 01/21] Update the AddToCartForm class to rely on a dedicated version of core's native templates for the simple and variable products. --- src/BlockTypes/AddToCartForm.php | 148 ++++++++++++++++++++++++++++--- 1 file changed, 138 insertions(+), 10 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 0a194d4a5b5..8664dd3e55a 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -15,6 +15,129 @@ class AddToCartForm extends AbstractBlock { */ protected $block_name = 'add-to-cart-form'; + /** + * Output the quantity input for add to cart form block. + */ + protected function get_quantity_input( $product ) { + return woocommerce_quantity_input( + array( + 'min_value' => apply_filters( 'woocommerce_quantity_input_min', $product->get_min_purchase_quantity(), $product ), + 'max_value' => apply_filters( 'woocommerce_quantity_input_max', $product->get_max_purchase_quantity(), $product ), + 'input_value' => isset( $_POST['quantity'] ) ? wc_stock_amount( wp_unslash( $_POST['quantity'] ) ) : $product->get_min_purchase_quantity(), // WPCS: CSRF ok, input var ok. + ), + $product + ); + } + protected function get_add_to_cart_button( $product ) { + return sprintf( + '', + esc_attr( $product->get_id() ), + esc_attr( wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '' ), + esc_html( $product->single_add_to_cart_text() ) + ); + } + protected function add_variable_product_to_cart( $product ) { + $attributes = $product->get_variation_attributes(); + $attribute_keys = array_keys( $attributes ); + $available_variations = $product->get_available_variations(); + $variations_json = wp_json_encode( $available_variations ); + $variations_attr = function_exists( 'wc_esc_json' ) ? wc_esc_json( $variations_json ) : _wp_specialchars( $variations_json, ENT_QUOTES, 'UTF-8', true ); + + do_action( 'woocommerce_before_add_to_cart_form' ); + + ob_start(); + + sprintf( + '
', + esc_url( apply_filters( 'woocommerce_add_to_cart_form_action', $product->get_permalink() ) ), + absint( $product->get_id() ), + $variations_attr + ); + + ?>
+ + + +

+ + + + $options ) : ?> + + + + + + + + + +
+ +
+ + + +
+ + is_purchasable() || ! $product->is_in_stock() ) { + return ''; + } + + echo wc_get_stock_html( $product ); // WPCS: XSS ok. + + do_action( 'woocommerce_before_add_to_cart_form' ); + $add_to_cart_form_action = esc_url( apply_filters( 'woocommerce_add_to_cart_form_action', $product->get_permalink() ) ); + + echo sprintf( + '
%2$s %3$s
', + $add_to_cart_form_action, + $this->get_quantity_input( $product ), + $this->get_add_to_cart_button( $product ) + ); + + do_action( 'woocommerce_after_add_to_cart_form' ); + + return ob_get_clean(); + } + /** * Render the block. * @@ -36,17 +159,22 @@ protected function render( $attributes, $content, $block ) { return ''; } - ob_start(); - /** - * Trigger the single product add to cart action for each product type. - * - * @since 9.7.0 - */ - do_action( 'woocommerce_' . $product->get_type() . '_add_to_cart' ); + $product_type = $product->get_type(); - $product = ob_get_clean(); + $render_product = ''; + switch ( $product_type ) { + case 'simple': + $render_product = $this->add_simple_product_to_cart( $product ); + break; + case 'variable': + $render_product = $this->add_variable_product_to_cart( $product ); + break; + case 2: + echo "i equals 2"; + break; + } - if ( ! $product ) { + if ( ! $render_product ) { return ''; } @@ -58,7 +186,7 @@ protected function render( $attributes, $content, $block ) { esc_attr( $classes_and_styles['classes'] ), esc_attr( $classname ), esc_attr( $classes_and_styles['styles'] ), - $product + $render_product ); } From d8734335394a9cb381fe07b8f5d2b1c0aff1996d Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Wed, 17 May 2023 14:27:21 +0200 Subject: [PATCH 02/21] Ditch the 'woocommerce_single_variation' action and invoke the variation-add-to-cart-button directly. --- src/BlockTypes/AddToCartForm.php | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 8664dd3e55a..e78c7fa12ee 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -89,16 +89,27 @@ protected function add_variable_product_to_cart( $product ) { * Hook: woocommerce_before_single_variation. */ do_action( 'woocommerce_before_single_variation' ); + ?> +
+
+ + get_quantity_input( $product ); + do_action( 'woocommerce_after_add_to_cart_quantity' ); + ?> + + + + + + + +
+
+ Date: Wed, 17 May 2023 15:00:55 +0200 Subject: [PATCH 03/21] update html structure for add_variable_product_to_cart --- src/BlockTypes/AddToCartForm.php | 60 +++++++++++++++++++------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index e78c7fa12ee..493d4706748 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -17,17 +17,25 @@ class AddToCartForm extends AbstractBlock { /** * Output the quantity input for add to cart form block. + * + * @param \WC_Product $product Product object. */ protected function get_quantity_input( $product ) { return woocommerce_quantity_input( array( 'min_value' => apply_filters( 'woocommerce_quantity_input_min', $product->get_min_purchase_quantity(), $product ), 'max_value' => apply_filters( 'woocommerce_quantity_input_max', $product->get_max_purchase_quantity(), $product ), - 'input_value' => isset( $_POST['quantity'] ) ? wc_stock_amount( wp_unslash( $_POST['quantity'] ) ) : $product->get_min_purchase_quantity(), // WPCS: CSRF ok, input var ok. + 'input_value' => isset( $_POST['quantity'] ) ? wc_stock_amount( wp_unslash( $_POST['quantity'] ) ) : $product->get_min_purchase_quantity(), ), $product ); } + + /** + * Output the add to cart button. + * + * @param \WC_Product $product Product object. + */ protected function get_add_to_cart_button( $product ) { return sprintf( '', @@ -36,6 +44,12 @@ protected function get_add_to_cart_button( $product ) { esc_html( $product->single_add_to_cart_text() ) ); } + + /** + * Output the add to cart form for a variable product. + * + * @param \WC_Product $product Product object. + */ protected function add_variable_product_to_cart( $product ) { $attributes = $product->get_variation_attributes(); $attribute_keys = array_keys( $attributes ); @@ -54,17 +68,17 @@ protected function add_variable_product_to_cart( $product ) { $variations_attr ); - ?>
+ ?> -

+

- + $options ) : ?> - + @@ -83,31 +97,30 @@ protected function add_variable_product_to_cart( $product ) { -
+
-
-
- -
+
+ + get_quantity_input( $product ); + $this->get_quantity_input( $product ); - do_action( 'woocommerce_after_add_to_cart_quantity' ); - ?> - + do_action( 'woocommerce_after_add_to_cart_quantity' ); + ?> + - + - - - -
+ + +
get_permalink() ) ); @@ -180,9 +193,6 @@ protected function render( $attributes, $content, $block ) { case 'variable': $render_product = $this->add_variable_product_to_cart( $product ); break; - case 2: - echo "i equals 2"; - break; } if ( ! $render_product ) { From 161d55e84e8bfba463e7844e6ce8c8e4f7e54bc1 Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Wed, 17 May 2023 15:17:29 +0200 Subject: [PATCH 04/21] Introduce the add_external_product_to_cart method and update the add_variable_product_to_cart method for enqueing 'wc-add-to-cart-variation'. --- src/BlockTypes/AddToCartForm.php | 47 +++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 493d4706748..e7f035de3ad 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -46,11 +46,15 @@ protected function get_add_to_cart_button( $product ) { } /** - * Output the add to cart form for a variable product. + * The add to cart form for a variable product. * * @param \WC_Product $product Product object. */ protected function add_variable_product_to_cart( $product ) { + // Enqueue variation scripts. + wp_enqueue_script( 'wc-add-to-cart-variation' ); + + // Get Available variations? $attributes = $product->get_variation_attributes(); $attribute_keys = array_keys( $attributes ); $available_variations = $product->get_available_variations(); @@ -140,6 +144,11 @@ protected function add_variable_product_to_cart( $product ) { return ob_get_clean(); } + /** + * The add to cart form for a simple product. + * + * @param \WC_Product $product Product object. + */ protected function add_simple_product_to_cart( $product ) { if ( ! $product->is_purchasable() || ! $product->is_in_stock() ) { return ''; @@ -162,6 +171,35 @@ protected function add_simple_product_to_cart( $product ) { return ob_get_clean(); } + /** + * The add to cart form for an external product. + * + * @param \WC_Product $product Product object. + */ + protected function add_external_product_to_cart( $product ) { + $add_to_cart_url = $product->add_to_cart_url(); + $button_text = $product->single_add_to_cart_text(); + + if ( ! $button_text || ! $add_to_cart_url ) { + return; + } + + do_action( 'woocommerce_before_add_to_cart_form' ); + ob_start(); ?> + + + + + + + + + + add_simple_product_to_cart( $product ); break; case 'variable': + case 'variation': $render_product = $this->add_variable_product_to_cart( $product ); break; + case 'grouped': + $render_product = $this->add_grouped_product_to_cart( $product ); + break; + case 'external': + $render_product = $this->add_external_product_to_cart( $product ); + break; } if ( ! $render_product ) { From b2b223a444f66da374084c974bc18fe9b7294cce Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Wed, 17 May 2023 15:27:17 +0200 Subject: [PATCH 05/21] Introduce the add_grouped_product_to_cart method. --- src/BlockTypes/AddToCartForm.php | 121 +++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index e7f035de3ad..e61019bf03b 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -200,6 +200,127 @@ protected function add_external_product_to_cart( $product ) { return ob_get_clean(); } + /** + * The add to cart form for a grouped product. + * + * @param \WC_Product $product Product object. + */ + protected function add_grouped_product_to_cart( $product ) { + $post = get_post( $product->get_id() ); + $grouped_products = array_filter( array_map( 'wc_get_product', $product->get_children() ), 'wc_products_array_filter_visible_grouped' ); + + do_action( 'woocommerce_before_add_to_cart_form' ); + + ob_start(); ?> + +
+ + + get_id() ); + $quantites_required = $quantites_required || ( $grouped_product_child->is_purchasable() && ! $grouped_product_child->has_options() ); + $post = $post_object; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + setup_postdata( $post ); + + if ( $grouped_product_child->is_in_stock() ) { + $show_add_to_cart_button = true; + } + + echo ''; + + // Output columns for each product. + foreach ( $grouped_product_columns as $column_id ) { + do_action( 'woocommerce_grouped_product_list_before_' . $column_id, $grouped_product_child ); + + switch ( $column_id ) { + case 'quantity': + ob_start(); + + if ( ! $grouped_product_child->is_purchasable() || $grouped_product_child->has_options() || ! $grouped_product_child->is_in_stock() ) { + woocommerce_template_loop_add_to_cart(); + } elseif ( $grouped_product_child->is_sold_individually() ) { + echo ''; + echo ''; + } else { + do_action( 'woocommerce_before_add_to_cart_quantity' ); + + woocommerce_quantity_input( + array( + 'input_name' => 'quantity[' . $grouped_product_child->get_id() . ']', + 'input_value' => isset( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ? wc_stock_amount( wc_clean( wp_unslash( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing + 'min_value' => apply_filters( 'woocommerce_quantity_input_min', 0, $grouped_product_child ), + 'max_value' => apply_filters( 'woocommerce_quantity_input_max', $grouped_product_child->get_max_purchase_quantity(), $grouped_product_child ), + 'placeholder' => '0', + ) + ); + + do_action( 'woocommerce_after_add_to_cart_quantity' ); + } + + $value = ob_get_clean(); + break; + case 'label': + $value = ''; + break; + case 'price': + $value = $grouped_product_child->get_price_html() . wc_get_stock_html( $grouped_product_child ); + break; + default: + $value = ''; + break; + } + + echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + + do_action( 'woocommerce_grouped_product_list_after_' . $column_id, $grouped_product_child ); + } + + echo ''; + } + $post = $previous_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + setup_postdata( $post ); + + do_action( 'woocommerce_grouped_product_list_after', $grouped_product_columns, $quantites_required, $product ); + ?> + +
' . apply_filters( 'woocommerce_grouped_product_list_column_' . $column_id, $value, $grouped_product_child ) . '
+ + + + + + + + + + + + +
+ + Date: Wed, 17 May 2023 15:29:11 +0200 Subject: [PATCH 06/21] ditch the 'variation' case. --- src/BlockTypes/AddToCartForm.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index e61019bf03b..6699df5988d 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -350,7 +350,6 @@ protected function render( $attributes, $content, $block ) { $render_product = $this->add_simple_product_to_cart( $product ); break; case 'variable': - case 'variation': $render_product = $this->add_variable_product_to_cart( $product ); break; case 'grouped': From 12240c5182d65fec8bc1a62a111e21c7f30a5bee Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Wed, 17 May 2023 17:06:39 +0200 Subject: [PATCH 07/21] Breakdown the method for rendering variable products and introduce the new variable_product_form method. --- src/BlockTypes/AddToCartForm.php | 153 ++++++++++++++----------------- 1 file changed, 70 insertions(+), 83 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 6699df5988d..ed54bde1df2 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -36,109 +36,94 @@ protected function get_quantity_input( $product ) { * * @param \WC_Product $product Product object. */ - protected function get_add_to_cart_button( $product ) { + protected function add_to_cart_button( $product, $name = "" ) { return sprintf( - '', + '', + esc_attr( $name ), esc_attr( $product->get_id() ), esc_attr( wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '' ), esc_html( $product->single_add_to_cart_text() ) ); } + protected function variable_product_form( $product, $attributes, $attribute_keys, $available_variations, $variations_json, $variations_attr ) { + ?>
+ + + +

+ + + + $options ) : ?> + + + + + + + + +
+ +
+
+ get_quantity_input( $product ); + do_action( 'woocommerce_after_add_to_cart_quantity' ); + + do_action( 'woocommerce_before_add_to_cart_button' ); + echo $this->add_to_cart_button( $product ); + do_action( 'woocommerce_after_add_to_cart_button' ); + ?> +
+ +
+ + + +
get_variation_attributes(); $attribute_keys = array_keys( $attributes ); $available_variations = $product->get_available_variations(); $variations_json = wp_json_encode( $available_variations ); - $variations_attr = function_exists( 'wc_esc_json' ) ? wc_esc_json( $variations_json ) : _wp_specialchars( $variations_json, ENT_QUOTES, 'UTF-8', true ); + $variations_attr = wc_esc_json( $variations_json ); do_action( 'woocommerce_before_add_to_cart_form' ); ob_start(); - - sprintf( - '
', - esc_url( apply_filters( 'woocommerce_add_to_cart_form_action', $product->get_permalink() ) ), - absint( $product->get_id() ), - $variations_attr - ); - - ?>
- - - -

- - - - $options ) : ?> - - - - - - - - - -
- -
-
- - get_quantity_input( $product ); - - do_action( 'woocommerce_after_add_to_cart_quantity' ); - ?> - - - - - - - -
- -
- - - -
- - variable_product_form( $product, $attributes, $attribute_keys, $available_variations, $variations_json, $variations_attr ); do_action( 'woocommerce_after_add_to_cart_form' ); return ob_get_clean(); @@ -163,7 +148,7 @@ protected function add_simple_product_to_cart( $product ) { '
%2$s %3$s
', $add_to_cart_form_action, $this->get_quantity_input( $product ), - $this->get_add_to_cart_button( $product ) + $this->add_to_cart_button( $product, "add-to-cart" ) ); do_action( 'woocommerce_after_add_to_cart_form' ); @@ -344,7 +329,6 @@ protected function render( $attributes, $content, $block ) { $product_type = $product->get_type(); - $render_product = ''; switch ( $product_type ) { case 'simple': $render_product = $this->add_simple_product_to_cart( $product ); @@ -358,6 +342,9 @@ protected function render( $attributes, $content, $block ) { case 'external': $render_product = $this->add_external_product_to_cart( $product ); break; + default: + $render_product = ''; + break; } if ( ! $render_product ) { From bf1d6abab355e9b6fe9daff1ab46326b9e22b98d Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Wed, 17 May 2023 17:49:46 +0200 Subject: [PATCH 08/21] Introduce the variable_inputs method and address PHPCS errors. --- src/BlockTypes/AddToCartForm.php | 73 +++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index ed54bde1df2..05624c9496b 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -35,8 +35,11 @@ protected function get_quantity_input( $product ) { * Output the add to cart button. * * @param \WC_Product $product Product object. + * @param string $name Name of the button. + * + * @return string */ - protected function add_to_cart_button( $product, $name = "" ) { + protected function add_to_cart_button( $product, $name = '' ) { return sprintf( '', esc_attr( $name ), @@ -46,8 +49,38 @@ protected function add_to_cart_button( $product, $name = "" ) { ); } + /** + * The inputs for an individual variable product. + * + * @param int $product_id Product ID. + * + * @return string + */ + protected function variable_inputs( $product_id ) { + return sprintf( + ' + + ', + absint( $product_id ) + ); + } + + /** + * The add to cart form for an individual variable product. + * + * @param \WC_Product $product Product object. + * @param array $attributes Array of attributes. + * @param array $attribute_keys Array of attribute keys. + * @param array $available_variations Array of available variations. + * @param string $variations_json JSON encoded string of variations. + * @param string $variations_attr HTML encoded string of variations. + * + * @return void + */ protected function variable_product_form( $product, $attributes, $attribute_keys, $available_variations, $variations_json, $variations_attr ) { - ?>
+ $product_id = $product->get_id(); + ?> + @@ -88,10 +121,10 @@ protected function variable_product_form( $product, $attributes, $attribute_keys do_action( 'woocommerce_before_add_to_cart_quantity' ); $this->get_quantity_input( $product ); do_action( 'woocommerce_after_add_to_cart_quantity' ); - do_action( 'woocommerce_before_add_to_cart_button' ); echo $this->add_to_cart_button( $product ); do_action( 'woocommerce_after_add_to_cart_button' ); + echo $this->variable_inputs( $product_id ); ?>
- - - + + %2$s %3$s', $add_to_cart_form_action, $this->get_quantity_input( $product ), - $this->add_to_cart_button( $product, "add-to-cart" ) + $this->add_to_cart_button( $product, 'add-to-cart' ) ); do_action( 'woocommerce_after_add_to_cart_form' ); @@ -173,15 +208,14 @@ protected function add_external_product_to_cart( $product ) { ob_start(); ?>
- - - - - +
- get_id() ); + $post = get_post( $product->get_id() ); $grouped_products = array_filter( array_map( 'wc_get_product', $product->get_children() ), 'wc_products_array_filter_visible_grouped' ); do_action( 'woocommerce_before_add_to_cart_form' ); - ob_start(); ?> - + ob_start(); + ?>
@@ -241,7 +275,7 @@ protected function add_grouped_product_to_cart( $product ) { woocommerce_template_loop_add_to_cart(); } elseif ( $grouped_product_child->is_sold_individually() ) { echo ''; - echo ''; + echo ''; } else { do_action( 'woocommerce_before_add_to_cart_quantity' ); @@ -301,7 +335,8 @@ protected function add_grouped_product_to_cart( $product ) { - Date: Wed, 17 May 2023 21:00:37 +0200 Subject: [PATCH 09/21] Make fine adjustments to the add_variable_product_to_cart method and the grouped_product_form method. --- src/BlockTypes/AddToCartForm.php | 91 +++++++++++++++++--------------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 05624c9496b..428bbc0528d 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -78,7 +78,10 @@ protected function variable_inputs( $product_id ) { * @return void */ protected function variable_product_form( $product, $attributes, $attribute_keys, $available_variations, $variations_json, $variations_attr ) { + ob_start(); $product_id = $product->get_id(); + + do_action( 'woocommerce_before_add_to_cart_form' ); ?> @@ -140,25 +143,6 @@ protected function variable_product_form( $product, $attributes, $attribute_keys ?> get_variation_attributes(); - $attribute_keys = array_keys( $attributes ); - $available_variations = $product->get_available_variations(); - $variations_json = wp_json_encode( $available_variations ); - $variations_attr = wc_esc_json( $variations_json ); - - do_action( 'woocommerce_before_add_to_cart_form' ); - - ob_start(); - $this->variable_product_form( $product, $attributes, $attribute_keys, $available_variations, $variations_json, $variations_attr ); do_action( 'woocommerce_after_add_to_cart_form' ); return ob_get_clean(); @@ -191,21 +175,42 @@ protected function add_simple_product_to_cart( $product ) { return ob_get_clean(); } + /** + * The add to cart form for a variable product. + * + * @param \WC_Product $product Product object. + * + * @return string + */ + protected function add_variable_product_to_cart( $product ) { + wp_enqueue_script( 'wc-add-to-cart-variation' ); + $attributes = $product->get_variation_attributes(); + $attribute_keys = array_keys( $attributes ); + $available_variations = $product->get_available_variations(); + $variations_json = wp_json_encode( $available_variations ); + $variations_attr = wc_esc_json( $variations_json ); + + return $this->variable_product_form( $product, $attributes, $attribute_keys, $available_variations, $variations_json, $variations_attr ); + } + /** * The add to cart form for an external product. * * @param \WC_Product $product Product object. + * + * return string */ protected function add_external_product_to_cart( $product ) { $add_to_cart_url = $product->add_to_cart_url(); $button_text = $product->single_add_to_cart_text(); if ( ! $button_text || ! $add_to_cart_url ) { - return; + return ''; } do_action( 'woocommerce_before_add_to_cart_form' ); - ob_start(); ?> + ob_start(); + ?> @@ -219,21 +224,12 @@ protected function add_external_product_to_cart( $product ) { return ob_get_clean(); } - /** - * The add to cart form for a grouped product. - * - * @param \WC_Product $product Product object. - */ - protected function add_grouped_product_to_cart( $product ) { - $post = get_post( $product->get_id() ); - $grouped_products = array_filter( array_map( 'wc_get_product', $product->get_children() ), 'wc_products_array_filter_visible_grouped' ); - - do_action( 'woocommerce_before_add_to_cart_form' ); - + protected function grouped_product_form( $product, $post, $grouped_products ) { ob_start(); + do_action( 'woocommerce_before_add_to_cart_form' ); ?> -
+
get_id() ); ?>" /> - - - - - - - - - + add_to_cart_button( $product ); + do_action( 'woocommerce_after_add_to_cart_button' ); + endif; + ?> - get_id() ); + $grouped_products = array_filter( array_map( 'wc_get_product', $product->get_children() ), 'wc_products_array_filter_visible_grouped' ); + + $this->grouped_product_form( $product, $post, $grouped_products ); + } + /** * Render the block. * From d10c7603a8918679321257229b156133ace20e5f Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Wed, 17 May 2023 21:13:27 +0200 Subject: [PATCH 10/21] Remove all filters. --- src/BlockTypes/AddToCartForm.php | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 428bbc0528d..6b63be25adc 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -23,8 +23,8 @@ class AddToCartForm extends AbstractBlock { protected function get_quantity_input( $product ) { return woocommerce_quantity_input( array( - 'min_value' => apply_filters( 'woocommerce_quantity_input_min', $product->get_min_purchase_quantity(), $product ), - 'max_value' => apply_filters( 'woocommerce_quantity_input_max', $product->get_max_purchase_quantity(), $product ), + 'min_value' => $product->get_min_purchase_quantity(), + 'max_value' => $product->get_max_purchase_quantity(), 'input_value' => isset( $_POST['quantity'] ) ? wc_stock_amount( wp_unslash( $_POST['quantity'] ) ) : $product->get_min_purchase_quantity(), ), $product @@ -83,11 +83,11 @@ protected function variable_product_form( $product, $attributes, $attribute_keys do_action( 'woocommerce_before_add_to_cart_form' ); ?> -
+ -

+

@@ -103,7 +103,7 @@ protected function variable_product_form( $product, $attributes, $attribute_keys 'product' => $product, ) ); - echo end( $attribute_keys ) === $attribute_name ? wp_kses_post( apply_filters( 'woocommerce_reset_variations_link', '' . esc_html__( 'Clear', 'woo-gutenberg-products-block' ) . '' ) ) : ''; + echo end( $attribute_keys ) === $attribute_name ? wp_kses_post( '' . esc_html__( 'Clear', 'woo-gutenberg-products-block' ) . '' ) : ''; ?> @@ -161,7 +161,7 @@ protected function add_simple_product_to_cart( $product ) { echo wc_get_stock_html( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped do_action( 'woocommerce_before_add_to_cart_form' ); - $add_to_cart_form_action = esc_url( apply_filters( 'woocommerce_add_to_cart_form_action', $product->get_permalink() ) ); + $add_to_cart_form_action = esc_url( $product->get_permalink() ); echo sprintf( '%2$s %3$s', @@ -228,21 +228,18 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { ob_start(); do_action( 'woocommerce_before_add_to_cart_form' ); ?> - + 'quantity[' . $grouped_product_child->get_id() . ']', 'input_value' => isset( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ? wc_stock_amount( wc_clean( wp_unslash( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing - 'min_value' => apply_filters( 'woocommerce_quantity_input_min', 0, $grouped_product_child ), - 'max_value' => apply_filters( 'woocommerce_quantity_input_max', $grouped_product_child->get_max_purchase_quantity(), $grouped_product_child ), + 'min_value' => 0, + 'max_value' => $grouped_product_child->get_max_purchase_quantity(), 'placeholder' => '0', ) ); @@ -292,7 +289,7 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { break; case 'label': $value = ''; break; case 'price': @@ -303,7 +300,7 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { break; } - echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped do_action( 'woocommerce_grouped_product_list_after_' . $column_id, $grouped_product_child ); } From 23aae77ef99f5ea0ea3097d7292e041c8958134d Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Wed, 17 May 2023 21:14:27 +0200 Subject: [PATCH 11/21] Update the add_grouped_product_to_cart method to return the grouped_product_form --- src/BlockTypes/AddToCartForm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 6b63be25adc..5ace4d7b44e 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -340,7 +340,7 @@ protected function add_grouped_product_to_cart( $product ) { $post = get_post( $product->get_id() ); $grouped_products = array_filter( array_map( 'wc_get_product', $product->get_children() ), 'wc_products_array_filter_visible_grouped' ); - $this->grouped_product_form( $product, $post, $grouped_products ); + return $this->grouped_product_form( $product, $post, $grouped_products ); } /** From ebaf44fdb414ca708484a99ae722b1fce10b6f4c Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Wed, 17 May 2023 21:56:08 +0200 Subject: [PATCH 12/21] Remove all repetitive occurences of woocommerce_before_add_to_cart_form, woocommerce_after_add_to_cart_form, woocommerce_before_add_to_cart_button, woocommerce_after_add_to_cart_button actions and consolidate the form render on a new method called add_to_cart_form. Add docblocks to all actions. --- src/BlockTypes/AddToCartForm.php | 198 +++++++++++++++++++++++-------- 1 file changed, 149 insertions(+), 49 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 5ace4d7b44e..09f79d82f1c 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -40,13 +40,29 @@ protected function get_quantity_input( $product ) { * @return string */ protected function add_to_cart_button( $product, $name = '' ) { - return sprintf( + ob_start(); + /** + * Hook: woocommerce_before_add_to_cart_button. + * + * @since TBD + */ + do_action( 'woocommerce_before_add_to_cart_button' ); + + echo sprintf( '', esc_attr( $name ), esc_attr( $product->get_id() ), esc_attr( wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '' ), esc_html( $product->single_add_to_cart_text() ) ); + + /** + * Hook: woocommerce_after_add_to_cart_button. + * + * @since TBD + */ + do_action( 'woocommerce_after_add_to_cart_button' ); + return ob_get_clean(); } /** @@ -65,6 +81,55 @@ protected function variable_inputs( $product_id ) { ); } + /** + * Return the Add to Cart Form for a given product. + * + * @param \WC_Product $product Product object. + * + * @return string + */ + protected function add_to_cart_form( $product ) { + $product_type = $product->get_type(); + + switch ( $product_type ) { + case 'simple': + $render_product = $this->add_simple_product_to_cart( $product ); + break; + case 'variable': + $render_product = $this->add_variable_product_to_cart( $product ); + break; + case 'grouped': + $render_product = $this->add_grouped_product_to_cart( $product ); + break; + case 'external': + $render_product = $this->add_external_product_to_cart( $product ); + break; + default: + $render_product = ''; + break; + } + + ob_start(); + + /** + * Hook: woocommerce_before_add_to_cart_form. + * + * @since TBD + */ + do_action( 'woocommerce_before_add_to_cart_form' ); + + echo $render_product; + + /** + * Hook: woocommerce_after_add_to_cart_form. + * + * @since TBD + */ + do_action( 'woocommerce_after_add_to_cart_form' ); + + return ob_get_clean(); + } + /** * The add to cart form for an individual variable product. * @@ -75,16 +140,21 @@ protected function variable_inputs( $product_id ) { * @param string $variations_json JSON encoded string of variations. * @param string $variations_attr HTML encoded string of variations. * - * @return void + * @return string */ protected function variable_product_form( $product, $attributes, $attribute_keys, $available_variations, $variations_json, $variations_attr ) { ob_start(); $product_id = $product->get_id(); - - do_action( 'woocommerce_before_add_to_cart_form' ); ?> - +

@@ -110,40 +180,63 @@ protected function variable_product_form( $product, $attributes, $attribute_keys
' . apply_filters( 'woocommerce_grouped_product_list_column_' . $column_id, $value, $grouped_product_child ) . '' . $value . '
- +
get_quantity_input( $product ); + /** + * Hook: woocommerce_after_add_to_cart_quantity. + * + * @since TBD + */ do_action( 'woocommerce_after_add_to_cart_quantity' ); - do_action( 'woocommerce_before_add_to_cart_button' ); echo $this->add_to_cart_button( $product ); - do_action( 'woocommerce_after_add_to_cart_button' ); echo $this->variable_inputs( $product_id ); ?>
get_permalink() ); echo sprintf( @@ -170,8 +261,6 @@ protected function add_simple_product_to_cart( $product ) { $this->add_to_cart_button( $product, 'add-to-cart' ) ); - do_action( 'woocommerce_after_add_to_cart_form' ); - return ob_get_clean(); } @@ -208,25 +297,29 @@ protected function add_external_product_to_cart( $product ) { return ''; } - do_action( 'woocommerce_before_add_to_cart_form' ); ob_start(); ?>
- - add_to_cart_button( $product ); wc_query_string_form_fields( $add_to_cart_url ); - do_action( 'woocommerce_after_add_to_cart_button' ); ?>
@@ -235,13 +328,18 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { $quantites_required = false; $previous_post = $post; $grouped_product_columns = array( - 'quantity', - 'label', - 'price', + 'quantity', + 'label', + 'price', ); $show_add_to_cart_button = false; + /** + * Hook: woocommerce_grouped_product_list_before. + * + * @since TBD + */ do_action( 'woocommerce_grouped_product_list_before', $grouped_product_columns, $quantites_required, $product ); foreach ( $grouped_products as $grouped_product_child ) { @@ -258,6 +356,11 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { // Output columns for each product. foreach ( $grouped_product_columns as $column_id ) { + /** + * Hook: woocommerce_grouped_product_list_before_{$column_id}. + * + * @since TBD + */ do_action( 'woocommerce_grouped_product_list_before_' . $column_id, $grouped_product_child ); switch ( $column_id ) { @@ -270,6 +373,11 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { echo ''; echo ''; } else { + /** + * Hook: woocommerce_before_add_to_cart_quantity. + * + * @since TBD + */ do_action( 'woocommerce_before_add_to_cart_quantity' ); woocommerce_quantity_input( @@ -282,6 +390,11 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { ) ); + /** + * Hook: woocommerce_after_add_to_cart_quantity. + * + * @since TBD + */ do_action( 'woocommerce_after_add_to_cart_quantity' ); } @@ -302,6 +415,11 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + /** + * Hook: woocommerce_grouped_product_list_after_{$column_id}. + * + * @since TBD + */ do_action( 'woocommerce_grouped_product_list_after_' . $column_id, $grouped_product_child ); } @@ -309,7 +427,11 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { } $post = $previous_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited setup_postdata( $post ); - + /** + * Hook: woocommerce_grouped_product_list_after. + * + * @since TBD + */ do_action( 'woocommerce_grouped_product_list_after', $grouped_product_columns, $quantites_required, $product ); ?> @@ -319,15 +441,11 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { add_to_cart_button( $product ); - do_action( 'woocommerce_after_add_to_cart_button' ); + echo $this->add_to_cart_button( $product ); endif; ?> get_type(); - - switch ( $product_type ) { - case 'simple': - $render_product = $this->add_simple_product_to_cart( $product ); - break; - case 'variable': - $render_product = $this->add_variable_product_to_cart( $product ); - break; - case 'grouped': - $render_product = $this->add_grouped_product_to_cart( $product ); - break; - case 'external': - $render_product = $this->add_external_product_to_cart( $product ); - break; - default: - $render_product = ''; - break; - } + $add_to_cart_form = $this->add_to_cart_form( $product ); - if ( ! $render_product ) { + if ( ! $add_to_cart_form ) { return ''; } @@ -396,7 +496,7 @@ protected function render( $attributes, $content, $block ) { esc_attr( $classes_and_styles['classes'] ), esc_attr( $classname ), esc_attr( $classes_and_styles['styles'] ), - $render_product + $add_to_cart_form ); } From 016cdc6b275b71cd51ac3a6340528783a8ca792e Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Wed, 17 May 2023 22:05:24 +0200 Subject: [PATCH 13/21] Reorder the methods. --- src/BlockTypes/AddToCartForm.php | 338 ++++++++++++++++--------------- 1 file changed, 170 insertions(+), 168 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 09f79d82f1c..387cf78d51e 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -15,6 +15,176 @@ class AddToCartForm extends AbstractBlock { */ protected $block_name = 'add-to-cart-form'; + /** + * Render the block. + * + * @param array $attributes Block attributes. + * @param string $content Block content. + * @param WP_Block $block Block instance. + * + * @return string | void Rendered block output. + */ + protected function render( $attributes, $content, $block ) { + $post_id = $block->context['postId']; + + if ( ! isset( $post_id ) ) { + return ''; + } + + $product = wc_get_product( $post_id ); + if ( ! $product instanceof \WC_Product ) { + return ''; + } + + $add_to_cart_form = $this->add_to_cart_form( $product ); + + if ( ! $add_to_cart_form ) { + return ''; + } + + $classname = $attributes['className'] ?? ''; + $classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes ); + + return sprintf( + '
%4$s
', + esc_attr( $classes_and_styles['classes'] ), + esc_attr( $classname ), + esc_attr( $classes_and_styles['styles'] ), + $add_to_cart_form + ); + } + + /** + * Return the Add to Cart Form for a given product. + * + * @param \WC_Product $product Product object. + * + * @return string + */ + protected function add_to_cart_form( $product ) { + $product_type = $product->get_type(); + + switch ( $product_type ) { + case 'simple': + $render_product = $this->add_simple_product_to_cart( $product ); + break; + case 'variable': + $render_product = $this->add_variable_product_to_cart( $product ); + break; + case 'grouped': + $render_product = $this->add_grouped_product_to_cart( $product ); + break; + case 'external': + $render_product = $this->add_external_product_to_cart( $product ); + break; + default: + $render_product = ''; + break; + } + + ob_start(); + + /** + * Hook: woocommerce_before_add_to_cart_form. + * + * @since TBD + */ + do_action( 'woocommerce_before_add_to_cart_form' ); + + echo $render_product; + + /** + * Hook: woocommerce_after_add_to_cart_form. + * + * @since TBD + */ + do_action( 'woocommerce_after_add_to_cart_form' ); + + return ob_get_clean(); + } + + /** + * The add to cart form for a simple product. + * + * @param \WC_Product $product Product object. + */ + protected function add_simple_product_to_cart( $product ) { + if ( ! $product->is_purchasable() || ! $product->is_in_stock() ) { + return ''; + } + + echo wc_get_stock_html( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + $add_to_cart_form_action = esc_url( $product->get_permalink() ); + + echo sprintf( + '
%2$s %3$s', + $add_to_cart_form_action, + $this->get_quantity_input( $product ), + $this->add_to_cart_button( $product, 'add-to-cart' ) + ); + + return ob_get_clean(); + } + + /** + * The add to cart form for a variable product. + * + * @param \WC_Product $product Product object. + * + * @return string + */ + protected function add_variable_product_to_cart( $product ) { + wp_enqueue_script( 'wc-add-to-cart-variation' ); + $attributes = $product->get_variation_attributes(); + $attribute_keys = array_keys( $attributes ); + $available_variations = $product->get_available_variations(); + $variations_json = wp_json_encode( $available_variations ); + $variations_attr = wc_esc_json( $variations_json ); + + return $this->variable_product_form( $product, $attributes, $attribute_keys, $available_variations, $variations_json, $variations_attr ); + } + + /** + * The add to cart form for a grouped product. + * + * @param \WC_Product $product Product object. + * + * @return string + */ + protected function add_grouped_product_to_cart( $product ) { + $post = get_post( $product->get_id() ); + $grouped_products = array_filter( array_map( 'wc_get_product', $product->get_children() ), 'wc_products_array_filter_visible_grouped' ); + + return $this->grouped_product_form( $product, $post, $grouped_products ); + } + + /** + * The add to cart form for an external product. + * + * @param \WC_Product $product Product object. + * + * return string + */ + protected function add_external_product_to_cart( $product ) { + $add_to_cart_url = $product->add_to_cart_url(); + $button_text = $product->single_add_to_cart_text(); + + if ( ! $button_text || ! $add_to_cart_url ) { + return ''; + } + + ob_start(); + ?> +
+ add_to_cart_button( $product ); + wc_query_string_form_fields( $add_to_cart_url ); + ?> + + get_type(); - - switch ( $product_type ) { - case 'simple': - $render_product = $this->add_simple_product_to_cart( $product ); - break; - case 'variable': - $render_product = $this->add_variable_product_to_cart( $product ); - break; - case 'grouped': - $render_product = $this->add_grouped_product_to_cart( $product ); - break; - case 'external': - $render_product = $this->add_external_product_to_cart( $product ); - break; - default: - $render_product = ''; - break; - } - - ob_start(); - - /** - * Hook: woocommerce_before_add_to_cart_form. - * - * @since TBD - */ - do_action( 'woocommerce_before_add_to_cart_form' ); - - echo $render_product; - - /** - * Hook: woocommerce_after_add_to_cart_form. - * - * @since TBD - */ - do_action( 'woocommerce_after_add_to_cart_form' ); - - return ob_get_clean(); - } - /** * The add to cart form for an individual variable product. * @@ -241,74 +362,6 @@ protected function variable_product_form( $product, $attributes, $attribute_keys return ob_get_clean(); } - /** - * The add to cart form for a simple product. - * - * @param \WC_Product $product Product object. - */ - protected function add_simple_product_to_cart( $product ) { - if ( ! $product->is_purchasable() || ! $product->is_in_stock() ) { - return ''; - } - - echo wc_get_stock_html( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - $add_to_cart_form_action = esc_url( $product->get_permalink() ); - - echo sprintf( - '
%2$s %3$s', - $add_to_cart_form_action, - $this->get_quantity_input( $product ), - $this->add_to_cart_button( $product, 'add-to-cart' ) - ); - - return ob_get_clean(); - } - - /** - * The add to cart form for a variable product. - * - * @param \WC_Product $product Product object. - * - * @return string - */ - protected function add_variable_product_to_cart( $product ) { - wp_enqueue_script( 'wc-add-to-cart-variation' ); - $attributes = $product->get_variation_attributes(); - $attribute_keys = array_keys( $attributes ); - $available_variations = $product->get_available_variations(); - $variations_json = wp_json_encode( $available_variations ); - $variations_attr = wc_esc_json( $variations_json ); - - return $this->variable_product_form( $product, $attributes, $attribute_keys, $available_variations, $variations_json, $variations_attr ); - } - - /** - * The add to cart form for an external product. - * - * @param \WC_Product $product Product object. - * - * return string - */ - protected function add_external_product_to_cart( $product ) { - $add_to_cart_url = $product->add_to_cart_url(); - $button_text = $product->single_add_to_cart_text(); - - if ( ! $button_text || ! $add_to_cart_url ) { - return ''; - } - - ob_start(); - ?> -
- add_to_cart_button( $product ); - wc_query_string_form_fields( $add_to_cart_url ); - ?> - - get_id() ); - $grouped_products = array_filter( array_map( 'wc_get_product', $product->get_children() ), 'wc_products_array_filter_visible_grouped' ); - - return $this->grouped_product_form( $product, $post, $grouped_products ); - } - - /** - * Render the block. - * - * @param array $attributes Block attributes. - * @param string $content Block content. - * @param WP_Block $block Block instance. - * - * @return string | void Rendered block output. - */ - protected function render( $attributes, $content, $block ) { - $post_id = $block->context['postId']; - - if ( ! isset( $post_id ) ) { - return ''; - } - - $product = wc_get_product( $post_id ); - if ( ! $product instanceof \WC_Product ) { - return ''; - } - - $add_to_cart_form = $this->add_to_cart_form( $product ); - - if ( ! $add_to_cart_form ) { - return ''; - } - - $classname = $attributes['className'] ?? ''; - $classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes ); - - return sprintf( - '
%4$s
', - esc_attr( $classes_and_styles['classes'] ), - esc_attr( $classname ), - esc_attr( $classes_and_styles['styles'] ), - $add_to_cart_form - ); - } - /** * Get the frontend script handle for this block type. * From 25be7e68e4a6fa96568039f8e62f329f75ddc65f Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Wed, 17 May 2023 22:14:56 +0200 Subject: [PATCH 14/21] Address phpcs errors. --- src/BlockTypes/AddToCartForm.php | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 387cf78d51e..48bd1fa8b6c 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -91,7 +91,7 @@ protected function add_to_cart_form( $product ) { */ do_action( 'woocommerce_before_add_to_cart_form' ); - echo $render_product; + echo $render_product; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped /** * Hook: woocommerce_after_add_to_cart_form. @@ -114,13 +114,12 @@ protected function add_simple_product_to_cart( $product ) { } echo wc_get_stock_html( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - $add_to_cart_form_action = esc_url( $product->get_permalink() ); echo sprintf( '
%2$s %3$s', - $add_to_cart_form_action, - $this->get_quantity_input( $product ), - $this->add_to_cart_button( $product, 'add-to-cart' ) + esc_url( $product->get_permalink() ), + $this->get_quantity_input( $product ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + $this->add_to_cart_button( $product, 'add-to-cart' ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ); return ob_get_clean(); @@ -163,7 +162,7 @@ protected function add_grouped_product_to_cart( $product ) { * * @param \WC_Product $product Product object. * - * return string + * @return string */ protected function add_external_product_to_cart( $product ) { $add_to_cart_url = $product->add_to_cart_url(); @@ -177,7 +176,7 @@ protected function add_external_product_to_cart( $product ) { ?>
add_to_cart_button( $product ); + echo $this->add_to_cart_button( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped wc_query_string_form_fields( $add_to_cart_url ); ?> @@ -334,8 +333,8 @@ protected function variable_product_form( $product, $attributes, $attribute_keys * @since TBD */ do_action( 'woocommerce_after_add_to_cart_quantity' ); - echo $this->add_to_cart_button( $product ); - echo $this->variable_inputs( $product_id ); + echo $this->add_to_cart_button( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo $this->variable_inputs( $product_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?> add_to_cart_button( $product ); + echo $this->add_to_cart_button( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped endif; ?> From 5c98547978c3761f9472c630c163a3a62bf855c0 Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Wed, 17 May 2023 22:22:56 +0200 Subject: [PATCH 15/21] update calls to the add_to_cart_button method. --- src/BlockTypes/AddToCartForm.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 48bd1fa8b6c..5f19cb3fa90 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -176,7 +176,7 @@ protected function add_external_product_to_cart( $product ) { ?>
add_to_cart_button( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + $this->add_to_cart_button( $product ); wc_query_string_form_fields( $add_to_cart_url ); ?> @@ -188,9 +188,11 @@ protected function add_external_product_to_cart( $product ) { * Output the quantity input for add to cart form block. * * @param \WC_Product $product Product object. + * + * @return void */ protected function get_quantity_input( $product ) { - return woocommerce_quantity_input( + echo woocommerce_quantity_input( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped array( 'min_value' => $product->get_min_purchase_quantity(), 'max_value' => $product->get_max_purchase_quantity(), @@ -206,10 +208,9 @@ protected function get_quantity_input( $product ) { * @param \WC_Product $product Product object. * @param string $name Name of the button. * - * @return string + * @return void */ protected function add_to_cart_button( $product, $name = '' ) { - ob_start(); /** * Hook: woocommerce_before_add_to_cart_button. * @@ -231,7 +232,6 @@ protected function add_to_cart_button( $product, $name = '' ) { * @since TBD */ do_action( 'woocommerce_after_add_to_cart_button' ); - return ob_get_clean(); } /** @@ -239,10 +239,10 @@ protected function add_to_cart_button( $product, $name = '' ) { * * @param int $product_id Product ID. * - * @return string + * @return void */ protected function variable_inputs( $product_id ) { - return sprintf( + echo sprintf( ' ', @@ -333,8 +333,8 @@ protected function variable_product_form( $product, $attributes, $attribute_keys * @since TBD */ do_action( 'woocommerce_after_add_to_cart_quantity' ); - echo $this->add_to_cart_button( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - echo $this->variable_inputs( $product_id ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + $this->add_to_cart_button( $product ); + $this->variable_inputs( $product_id ); ?> add_to_cart_button( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + $this->add_to_cart_button( $product ); endif; ?> From 21bfe5fd744af925177c438a49aef685564f14eb Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Thu, 18 May 2023 12:25:47 +0200 Subject: [PATCH 16/21] Ensure grouped products also rely on the get_quantity_input method for outputing the quantity. --- src/BlockTypes/AddToCartForm.php | 91 +++++++++++++++----------------- 1 file changed, 43 insertions(+), 48 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 5f19cb3fa90..9f72c3cbed8 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -66,19 +66,19 @@ protected function add_to_cart_form( $product ) { switch ( $product_type ) { case 'simple': - $render_product = $this->add_simple_product_to_cart( $product ); + $add_to_cart_form = $this->add_simple_product_to_cart( $product ); break; case 'variable': - $render_product = $this->add_variable_product_to_cart( $product ); + $add_to_cart_form = $this->add_variable_product_to_cart( $product ); break; case 'grouped': - $render_product = $this->add_grouped_product_to_cart( $product ); + $add_to_cart_form = $this->add_grouped_product_to_cart( $product ); break; case 'external': - $render_product = $this->add_external_product_to_cart( $product ); + $add_to_cart_form = $this->add_external_product_to_cart( $product ); break; default: - $render_product = ''; + $add_to_cart_form = ''; break; } @@ -91,7 +91,7 @@ protected function add_to_cart_form( $product ) { */ do_action( 'woocommerce_before_add_to_cart_form' ); - echo $render_product; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo $add_to_cart_form; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped /** * Hook: woocommerce_after_add_to_cart_form. @@ -187,19 +187,48 @@ protected function add_external_product_to_cart( $product ) { /** * Output the quantity input for add to cart form block. * - * @param \WC_Product $product Product object. + * @param \WC_Product $product Product object. + * @param string $product_type Product type. + * @param \WC_Product|null $grouped_product_child Child product object. * * @return void */ - protected function get_quantity_input( $product ) { - echo woocommerce_quantity_input( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - array( + protected function get_quantity_input( $product, $product_type = 'simple', $grouped_product_child = null ) { + if ( 'simple' === $product_type || 'variable' === $product_type ) { + $args = [ 'min_value' => $product->get_min_purchase_quantity(), 'max_value' => $product->get_max_purchase_quantity(), 'input_value' => isset( $_POST['quantity'] ) ? wc_stock_amount( wp_unslash( $_POST['quantity'] ) ) : $product->get_min_purchase_quantity(), - ), - $product - ); + ]; + } elseif ( 'grouped' === $product_type ) { + if ( ! $grouped_product_child ) { + return; + } + + $args = [ + 'input_name' => 'quantity[' . $grouped_product_child->get_id() . ']', + 'input_value' => isset( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ? wc_stock_amount( wc_clean( wp_unslash( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing + 'min_value' => 0, + 'max_value' => $grouped_product_child->get_max_purchase_quantity(), + 'placeholder' => '0', + ]; + } + + /** + * Hook: woocommerce_before_add_to_cart_quantity. + * + * @since TBD + */ + do_action( 'woocommerce_before_add_to_cart_quantity' ); + + echo woocommerce_quantity_input( $args, $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + + /** + * Hook: woocommerce_after_add_to_cart_quantity. + * + * @since TBD + */ + do_action( 'woocommerce_after_add_to_cart_quantity' ); } /** @@ -320,19 +349,7 @@ protected function variable_product_form( $product, $attributes, $attribute_keys
get_quantity_input( $product ); - /** - * Hook: woocommerce_after_add_to_cart_quantity. - * - * @since TBD - */ - do_action( 'woocommerce_after_add_to_cart_quantity' ); $this->add_to_cart_button( $product ); $this->variable_inputs( $product_id ); ?> @@ -425,29 +442,7 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { echo ''; echo ''; } else { - /** - * Hook: woocommerce_before_add_to_cart_quantity. - * - * @since TBD - */ - do_action( 'woocommerce_before_add_to_cart_quantity' ); - - woocommerce_quantity_input( - array( - 'input_name' => 'quantity[' . $grouped_product_child->get_id() . ']', - 'input_value' => isset( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ? wc_stock_amount( wc_clean( wp_unslash( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing - 'min_value' => 0, - 'max_value' => $grouped_product_child->get_max_purchase_quantity(), - 'placeholder' => '0', - ) - ); - - /** - * Hook: woocommerce_after_add_to_cart_quantity. - * - * @since TBD - */ - do_action( 'woocommerce_after_add_to_cart_quantity' ); + $this->get_quantity_input( $product, 'grouped', $grouped_product_child ); } $value = ob_get_clean(); From 7e15e23d59478d67627a46e7bb5cc4cdb9b5ee7a Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Thu, 18 May 2023 13:28:59 +0200 Subject: [PATCH 17/21] Ignore nonce verification. --- src/BlockTypes/AddToCartForm.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 9f72c3cbed8..5e038450d0c 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -195,19 +195,25 @@ protected function add_external_product_to_cart( $product ) { */ protected function get_quantity_input( $product, $product_type = 'simple', $grouped_product_child = null ) { if ( 'simple' === $product_type || 'variable' === $product_type ) { + // phpcs:ignore WordPress.Security.NonceVerification.Missing + $input_value = isset( $_POST['quantity'] ) ? wc_stock_amount( wp_unslash( $_POST['quantity'] ) ) : $product->get_min_purchase_quantity(); + $args = [ 'min_value' => $product->get_min_purchase_quantity(), 'max_value' => $product->get_max_purchase_quantity(), - 'input_value' => isset( $_POST['quantity'] ) ? wc_stock_amount( wp_unslash( $_POST['quantity'] ) ) : $product->get_min_purchase_quantity(), + 'input_value' => $input_value, ]; } elseif ( 'grouped' === $product_type ) { if ( ! $grouped_product_child ) { return; } + // phpcs:ignore WordPress.Security.NonceVerification.Missing + $input_value = isset( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ? wc_stock_amount( wc_clean( wp_unslash( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ) ) : ''; + $args = [ 'input_name' => 'quantity[' . $grouped_product_child->get_id() . ']', - 'input_value' => isset( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ? wc_stock_amount( wc_clean( wp_unslash( $_POST['quantity'][ $grouped_product_child->get_id() ] ) ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Missing + 'input_value' => $input_value, 'min_value' => 0, 'max_value' => $grouped_product_child->get_max_purchase_quantity(), 'placeholder' => '0', From d7dada474445f82ea60371efd7b215faf1ff0964 Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Thu, 18 May 2023 14:08:37 +0200 Subject: [PATCH 18/21] Ensure the add to cart form is properly rendered for simple products. --- src/BlockTypes/AddToCartForm.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 5e038450d0c..ed243531899 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -113,14 +113,16 @@ protected function add_simple_product_to_cart( $product ) { return ''; } + ob_start(); echo wc_get_stock_html( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - - echo sprintf( - '
%2$s %3$s', - esc_url( $product->get_permalink() ), - $this->get_quantity_input( $product ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - $this->add_to_cart_button( $product, 'add-to-cart' ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - ); + ?> +
+ get_quantity_input( $product ); + $this->add_to_cart_button( $product, 'add-to-cart' ); + ?> + + Date: Tue, 23 May 2023 19:59:34 +0200 Subject: [PATCH 19/21] Address code review feedback by removing multiple occurrences of phpcs:ignore and ensuring variables are properly sanitized. --- src/BlockTypes/AddToCartForm.php | 100 ++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 35 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 6d7b7e70cf8..6554f401d48 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -82,25 +82,7 @@ protected function add_to_cart_form( $product ) { break; } - ob_start(); - - /** - * Hook: woocommerce_before_add_to_cart_form. - * - * @since TBD - */ - do_action( 'woocommerce_before_add_to_cart_form' ); - - echo $add_to_cart_form; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - - /** - * Hook: woocommerce_after_add_to_cart_form. - * - * @since TBD - */ - do_action( 'woocommerce_after_add_to_cart_form' ); - - return ob_get_clean(); + return $add_to_cart_form; } /** @@ -114,7 +96,14 @@ protected function add_simple_product_to_cart( $product ) { } ob_start(); - echo wc_get_stock_html( $product ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + /** + * Hook: woocommerce_before_add_to_cart_form. + * + * @since TBD + */ + do_action( 'woocommerce_before_add_to_cart_form' ); + + echo wp_kses_post( wc_get_stock_html( $product ) ); ?>
get_variation_attributes(); $attribute_keys = array_keys( $attributes ); $available_variations = $product->get_available_variations(); - $variations_json = wp_json_encode( $available_variations ); - $variations_attr = wc_esc_json( $variations_json ); + $variations_attr = wp_json_encode( $available_variations ); - return $this->variable_product_form( $product, $attributes, $attribute_keys, $available_variations, $variations_json, $variations_attr ); + return $this->variable_product_form( $product, $attributes, $attribute_keys, $available_variations, $variations_attr ); } /** @@ -175,6 +169,12 @@ protected function add_external_product_to_cart( $product ) { } ob_start(); + /** + * Hook: woocommerce_before_add_to_cart_form. + * + * @since TBD + */ + do_action( 'woocommerce_before_add_to_cart_form' ); ?>
get_id(); ?> -
+ $options ) : ?>
- + get_id() ); $quantities_required = $quantities_required || ( $grouped_product_child->is_purchasable() && ! $grouped_product_child->has_options() ); - $post = $post_object; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited - setup_postdata( $post ); if ( $grouped_product_child->is_in_stock() ) { $show_add_to_cart_button = true; @@ -504,8 +500,6 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { echo ''; } - $post = $previous_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited - setup_postdata( $post ); /** * Hook: woocommerce_grouped_product_list_after. *
' . $value . '
get_id() ); - $quantites_required = $quantites_required || ( $grouped_product_child->is_purchasable() && ! $grouped_product_child->has_options() ); - $post = $post_object; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + $post_object = get_post( $grouped_product_child->get_id() ); + $quantities_required = $quantities_required || ( $grouped_product_child->is_purchasable() && ! $grouped_product_child->has_options() ); + $post = $post_object; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited setup_postdata( $post ); if ( $grouped_product_child->is_in_stock() ) { @@ -487,7 +511,7 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { * * @since TBD */ - do_action( 'woocommerce_grouped_product_list_after', $grouped_product_columns, $quantites_required, $product ); + do_action( 'woocommerce_grouped_product_list_after', $grouped_product_columns, $quantities_required, $product ); ?>
@@ -495,12 +519,18 @@ protected function grouped_product_form( $product, $post, $grouped_products ) { add_to_cart_button( $product ); endif; ?>
Date: Tue, 23 May 2023 20:04:53 +0200 Subject: [PATCH 20/21] Update the wp-block-add-to-cart-form class. --- src/BlockTypes/AddToCartForm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 6554f401d48..7ea126b13b5 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -46,7 +46,7 @@ protected function render( $attributes, $content, $block ) { $classes_and_styles = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes ); return sprintf( - '
%4$s
', + '
%4$s
', esc_attr( $classes_and_styles['classes'] ), esc_attr( $classname ), esc_attr( $classes_and_styles['styles'] ), From cbdd328592d205b7e06123f14baf9f2117f56d63 Mon Sep 17 00:00:00 2001 From: Patricia Hillebrandt Date: Tue, 23 May 2023 21:12:41 +0200 Subject: [PATCH 21/21] Ditch global variable override from the grouped_product_form method. --- src/BlockTypes/AddToCartForm.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index 7ea126b13b5..9677db846d2 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -427,7 +427,6 @@ protected function grouped_product_form( $product, $post, $grouped_products ) {