diff --git a/src/BlockTypes/AddToCartForm.php b/src/BlockTypes/AddToCartForm.php index ed161525904..9677db846d2 100644 --- a/src/BlockTypes/AddToCartForm.php +++ b/src/BlockTypes/AddToCartForm.php @@ -36,17 +36,9 @@ 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' ); + $add_to_cart_form = $this->add_to_cart_form( $product ); - $product = ob_get_clean(); - - if ( ! $product ) { + if ( ! $add_to_cart_form ) { return ''; } @@ -54,12 +46,486 @@ 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'] ), - $product + $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': + $add_to_cart_form = $this->add_simple_product_to_cart( $product ); + break; + case 'variable': + $add_to_cart_form = $this->add_variable_product_to_cart( $product ); + break; + case 'grouped': + $add_to_cart_form = $this->add_grouped_product_to_cart( $product ); + break; + case 'external': + $add_to_cart_form = $this->add_external_product_to_cart( $product ); + break; + default: + $add_to_cart_form = ''; + break; + } + + return $add_to_cart_form; + } + + /** + * 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 ''; + } + + ob_start(); + /** + * 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_quantity_input( $product ); + $this->add_to_cart_button( $product, 'add-to-cart' ); + ?> +
+ get_variation_attributes(); + $attribute_keys = array_keys( $attributes ); + $available_variations = $product->get_available_variations(); + $variations_attr = wp_json_encode( $available_variations ); + + return $this->variable_product_form( $product, $attributes, $attribute_keys, $available_variations, $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(); + /** + * Hook: woocommerce_before_add_to_cart_form. + * + * @since TBD + */ + do_action( 'woocommerce_before_add_to_cart_form' ); + ?> +
+ add_to_cart_button( $product ); + wc_query_string_form_fields( $add_to_cart_url ); + ?> +
+ get_min_purchase_quantity(); + + $args = [ + 'min_value' => $product->get_min_purchase_quantity(), + 'max_value' => $product->get_max_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' => $input_value, + '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 wp_kses_post( woocommerce_quantity_input( $args, $product ) ); + + /** + * Hook: woocommerce_after_add_to_cart_quantity. + * + * @since TBD + */ + do_action( 'woocommerce_after_add_to_cart_quantity' ); + } + + /** + * Output the add to cart button. + * + * @param \WC_Product $product Product object. + * @param string $name Name of the button. + * + * @return void + */ + protected function add_to_cart_button( $product, $name = '' ) { + /** + * 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' ); + } + + /** + * The inputs for an individual variable product. + * + * @param int $product_id Product ID. + * + * @return void + */ + protected function variable_inputs( $product_id ) { + echo 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_attr HTML encoded string of variations. + * + * @return string + */ + protected function variable_product_form( $product, $attributes, $attribute_keys, $available_variations, $variations_attr ) { + ob_start(); + /** + * Hook: woocommerce_before_add_to_cart_form. + * + * @since TBD + */ + do_action( 'woocommerce_before_add_to_cart_form' ); + + $product_id = $product->get_id(); + ?> +
+ + + +

+ + + + $options ) : ?> + + + + + + + + +
+ +
+
+ get_quantity_input( $product ); + $this->add_to_cart_button( $product ); + $this->variable_inputs( $product_id ); + ?> +
+ +
+ + +
+ +
+ + + is_purchasable() && ! $grouped_product_child->has_options() ); + + 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 ) { + /** + * 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 ) { + 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 { + $this->get_quantity_input( $product, 'grouped', $grouped_product_child ); + } + + $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 + + /** + * Hook: woocommerce_grouped_product_list_after_{$column_id}. + * + * @since TBD + */ + do_action( 'woocommerce_grouped_product_list_after_' . $column_id, $grouped_product_child ); + } + + echo ''; + } + /** + * Hook: woocommerce_grouped_product_list_after. + * + * @since TBD + */ + do_action( 'woocommerce_grouped_product_list_after', $grouped_product_columns, $quantities_required, $product ); + ?> + +
' . $value . '
+ + + + add_to_cart_button( $product ); + endif; + ?> +
+