diff --git a/assets/js/atomic/blocks/product-elements/button/attributes.js b/assets/js/atomic/blocks/product-elements/button/attributes.js
index 5bac8820c40..2e6189b1083 100644
--- a/assets/js/atomic/blocks/product-elements/button/attributes.js
+++ b/assets/js/atomic/blocks/product-elements/button/attributes.js
@@ -3,6 +3,10 @@ export const blockAttributes = {
type: 'number',
default: 0,
},
+ isDescendentOfQueryLoop: {
+ type: 'boolean',
+ default: false,
+ },
};
export default blockAttributes;
diff --git a/assets/js/atomic/blocks/product-elements/button/edit.js b/assets/js/atomic/blocks/product-elements/button/edit.js
index 2f4a7155fea..df93edad8fa 100644
--- a/assets/js/atomic/blocks/product-elements/button/edit.js
+++ b/assets/js/atomic/blocks/product-elements/button/edit.js
@@ -1,33 +1,30 @@
/**
* External dependencies
*/
-import { __ } from '@wordpress/i18n';
import { Disabled } from '@wordpress/components';
import { useBlockProps } from '@wordpress/block-editor';
+import { useEffect } from 'react';
/**
* Internal dependencies
*/
import Block from './block';
-import withProductSelector from '../shared/with-product-selector';
-import { BLOCK_TITLE, BLOCK_ICON } from './constants';
-const Edit = ( { attributes } ) => {
+const Edit = ( { attributes, setAttributes, context } ) => {
const blockProps = useBlockProps();
+ const isDescendentOfQueryLoop = Number.isFinite( context.queryId );
+
+ useEffect(
+ () => setAttributes( { isDescendentOfQueryLoop } ),
+ [ setAttributes, isDescendentOfQueryLoop ]
+ );
return (
-
+
);
};
-export default withProductSelector( {
- icon: BLOCK_ICON,
- label: BLOCK_TITLE,
- description: __(
- 'Choose a product to display its add to cart button.',
- 'woo-gutenberg-products-block'
- ),
-} )( Edit );
+export default Edit;
diff --git a/assets/js/atomic/blocks/product-elements/button/index.js b/assets/js/atomic/blocks/product-elements/button/index.js
index 64e42c82082..a177c1b6c75 100644
--- a/assets/js/atomic/blocks/product-elements/button/index.js
+++ b/assets/js/atomic/blocks/product-elements/button/index.js
@@ -15,17 +15,22 @@ import {
BLOCK_DESCRIPTION as description,
} from './constants';
import { supports } from './supports';
-import { Save } from '../title/save';
const blockConfig = {
apiVersion: 2,
title,
description,
+ parent: [ 'core/group' ],
+ ancestor: [
+ '@woocommerce/all-products',
+ '@woocommerce/single-product',
+ 'core/post-template',
+ ],
+ usesContext: [ 'query', 'queryId', 'postId' ],
icon: { src: icon },
attributes,
supports,
edit,
- save: Save,
};
registerBlockType( 'woocommerce/product-button', {
diff --git a/assets/js/atomic/blocks/product-elements/button/style.scss b/assets/js/atomic/blocks/product-elements/button/style.scss
index c4a28092e7b..f6dc0866f1c 100644
--- a/assets/js/atomic/blocks/product-elements/button/style.scss
+++ b/assets/js/atomic/blocks/product-elements/button/style.scss
@@ -36,3 +36,7 @@
border-color: var(--button--color-background);
}
}
+
+.wp-block-button.wc-block-components-product-button[data-is-descendent-of-query-loop="true"] {
+ text-align: center;
+}
diff --git a/src/BlockTypes/ProductButton.php b/src/BlockTypes/ProductButton.php
index 033d5334ea5..855ba3618d6 100644
--- a/src/BlockTypes/ProductButton.php
+++ b/src/BlockTypes/ProductButton.php
@@ -1,6 +1,8 @@
register_chunk_translations( [ $this->block_name ] );
+ return null;
+ }
+
+ /**
+ * Register the context.
+ */
+ protected function get_block_type_uses_context() {
+ return [ 'query', 'queryId', 'postId' ];
+ }
+
+ /**
+ * Include and render the block
+ *
+ * @param array $attributes Block attributes. Default empty array.
+ * @param string $content Block content. Default empty string.
+ * @param WP_Block $block Block instance.
+ * @return string Rendered block type output.
+ */
+ protected function render( $attributes, $content, $block ) {
+ if ( ! empty( $content ) ) {
+ parent::register_block_type_assets();
+ $this->register_chunk_translations( [ $this->block_name ] );
+ return $content;
+ }
+
+ $post_id = $block->context['postId'];
+ $product = wc_get_product( $post_id );
+
+ if ( $product ) {
+ $cart_redirect_after_add = get_option( 'woocommerce_cart_redirect_after_add' ) === 'yes';
+ $html_element = ( ! $product->has_options() && $product->is_purchasable() && $product->is_in_stock() && ! $cart_redirect_after_add ) ? 'button' : 'a';
+ $styles_and_classes = StyleAttributesUtils::get_classes_and_styles_by_attributes( $attributes, array( 'border_radius', 'font_size', 'text_color' ) );
+
+ return apply_filters(
+ 'woocommerce_loop_add_to_cart_link',
+ sprintf(
+ '
+ <%s href="%s" rel="nofollow" data-product_id="%s" data-product_sku="%s" class="wp-block-button__link %s wc-block-components-product-button__button product_type_%s %s" style="%s">%s%s>
+
',
+ $html_element,
+ esc_url( $product->add_to_cart_url() ),
+ esc_attr( $product->get_id() ),
+ esc_attr( $product->get_sku() ),
+ $product->is_purchasable() ? 'ajax_add_to_cart add_to_cart_button' : '',
+ esc_attr( $product->get_type() ),
+ $styles_and_classes['classes'],
+ $styles_and_classes['styles'],
+ esc_html( $product->add_to_cart_text() ),
+ $html_element
+ ),
+ $product
+ );
+ }
}
}