Merged in feature/MAW-855-import-code-into-aws (pull request #2)

code import from pantheon

* code import from pantheon
This commit is contained in:
Tony Volpe
2023-12-04 23:08:14 +00:00
parent 8c9b1312bc
commit 8f4b5efda6
4766 changed files with 185592 additions and 239967 deletions

View File

@@ -23,7 +23,6 @@ abstract class AbstractPageTemplate {
*/
protected function init() {
add_filter( 'page_template_hierarchy', array( $this, 'page_template_hierarchy' ), 1 );
add_action( 'current_screen', array( $this, 'page_template_editor_redirect' ) );
add_filter( 'pre_get_document_title', array( $this, 'page_template_title' ) );
}
@@ -39,14 +38,7 @@ abstract class AbstractPageTemplate {
*
* @return \WP_Post|null Post object or null.
*/
abstract public static function get_placeholder_page();
/**
* Should return the title of the page.
*
* @return string
*/
abstract public static function get_template_title();
abstract protected function get_placeholder_page();
/**
* Should return true on pages/endpoints/routes where the template should be shown.
@@ -56,12 +48,12 @@ abstract class AbstractPageTemplate {
abstract protected function is_active_template();
/**
* Returns the URL to edit the template.
* Should return the title of the page, or an empty string if the page title should not be changed.
*
* @return string
*/
protected function get_edit_template_url() {
return admin_url( 'site-editor.php?postType=wp_template&postId=woocommerce%2Fwoocommerce%2F%2F' . $this->get_slug() );
public static function get_template_title() {
return '';
}
/**
@@ -80,21 +72,6 @@ abstract class AbstractPageTemplate {
return $templates;
}
/**
* Redirect the edit page screen to the template editor.
*
* @param \WP_Screen $current_screen Current screen information.
*/
public function page_template_editor_redirect( \WP_Screen $current_screen ) {
$page = $this->get_placeholder_page();
$edit_page_id = 'page' === $current_screen->id && ! empty( $_GET['post'] ) ? absint( $_GET['post'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( $page && $edit_page_id === $page->ID ) {
wp_safe_redirect( $this->get_edit_template_url() );
exit;
}
}
/**
* Filter the page title when the template is active.
*
@@ -102,7 +79,7 @@ abstract class AbstractPageTemplate {
* @return string
*/
public function page_template_title( $title ) {
if ( $this->is_active_template() ) {
if ( $this->is_active_template() && $this->get_template_title() ) {
return $this->get_template_title();
}
return $title;

View File

@@ -103,7 +103,7 @@ abstract class AbstractTemplateCompatibility {
* The array format:
* [
* <hook-name> => [
* block_name => <block-name>,
* block_names => [ <block-name>, ... ],
* position => before|after,
* hooked => [
* <function-name> => <priority>,
@@ -113,7 +113,7 @@ abstract class AbstractTemplateCompatibility {
* ]
* Where:
* - hook-name is the name of the hook that will be replaced.
* - block-name is the name of the block that will replace the hook.
* - block-names is the array block names that hook will be attached to.
* - position is the position of the block relative to the hook.
* - hooked is an array of functions hooked to the hook that will be
* replaced. The key is the function name and the value is the

View File

@@ -47,7 +47,7 @@ class ArchiveProductTemplatesCompatibility extends AbstractTemplateCompatibility
return $parsed_block;
}
array_walk( $parsed_block['innerBlocks'], array( $this, 'inner_blocks_walker' ) );
$this->inner_blocks_walker( $parsed_block );
return $parsed_block;
}
@@ -72,16 +72,20 @@ class ArchiveProductTemplatesCompatibility extends AbstractTemplateCompatibility
$block_name = $block['blockName'];
if ( $this->is_null_post_template( $block ) ) {
$block_name = self::LOOP_ITEM_ID;
}
$block_hooks = array_filter(
$this->hook_data,
function( $hook ) use ( $block_name ) {
return $hook['block_name'] === $block_name;
return in_array( $block_name, $hook['block_names'], true );
}
);
// We want to inject hooks to the core/post-template block only when the products exist:
// We want to inject hooks to the core/post-template or product template block only when the products exist:
// https://github.com/woocommerce/woocommerce-blocks/issues/9463.
if ( 'core/post-template' === $block_name && ! empty( $block_content ) ) {
if ( $this->is_post_or_product_template( $block_name ) && ! empty( $block_content ) ) {
$this->restore_default_hooks();
$content = sprintf(
'%1$s%2$s%3$s',
@@ -93,24 +97,14 @@ class ArchiveProductTemplatesCompatibility extends AbstractTemplateCompatibility
return $content;
}
/**
* The core/post-template has two different block names:
* - core/post-template when the wrapper is rendered.
* - core/null when the loop item is rendered.
*/
if (
'core/null' === $block_name &&
isset( $block['attrs']['__woocommerceNamespace'] ) &&
'woocommerce/product-query/product-template' === $block['attrs']['__woocommerceNamespace']
) {
$block_name = self::LOOP_ITEM_ID;
}
$supported_blocks = array_map(
function( $hook ) {
return $hook['block_name'];
},
array_values( $this->hook_data )
$supported_blocks = array_merge(
[],
...array_map(
function( $hook ) {
return $hook['block_names'];
},
array_values( $this->hook_data )
)
);
if ( ! in_array( $block_name, $supported_blocks, true ) ) {
@@ -144,6 +138,10 @@ class ArchiveProductTemplatesCompatibility extends AbstractTemplateCompatibility
return $content;
}
if ( empty( $block_content ) ) {
return $block_content;
}
return sprintf(
'%1$s%2$s%3$s',
$this->get_hooks_buffer( $block_hooks, 'before' ),
@@ -182,60 +180,60 @@ class ArchiveProductTemplatesCompatibility extends AbstractTemplateCompatibility
protected function set_hook_data() {
$this->hook_data = array(
'woocommerce_before_main_content' => array(
'block_name' => 'core/query',
'position' => 'before',
'hooked' => array(
'block_names' => array( 'core/query', 'woocommerce/product-collection' ),
'position' => 'before',
'hooked' => array(
'woocommerce_output_content_wrapper' => 10,
'woocommerce_breadcrumb' => 20,
),
),
'woocommerce_after_main_content' => array(
'block_name' => 'core/query',
'position' => 'after',
'hooked' => array(
'block_names' => array( 'core/query', 'woocommerce/product-collection' ),
'position' => 'after',
'hooked' => array(
'woocommerce_output_content_wrapper_end' => 10,
),
),
'woocommerce_before_shop_loop_item_title' => array(
'block_name' => 'core/post-title',
'position' => 'before',
'hooked' => array(
'block_names' => array( 'core/post-title' ),
'position' => 'before',
'hooked' => array(
'woocommerce_show_product_loop_sale_flash' => 10,
'woocommerce_template_loop_product_thumbnail' => 10,
),
),
'woocommerce_shop_loop_item_title' => array(
'block_name' => 'core/post-title',
'position' => 'after',
'hooked' => array(
'block_names' => array( 'core/post-title' ),
'position' => 'after',
'hooked' => array(
'woocommerce_template_loop_product_title' => 10,
),
),
'woocommerce_after_shop_loop_item_title' => array(
'block_name' => 'core/post-title',
'position' => 'after',
'hooked' => array(
'block_names' => array( 'core/post-title' ),
'position' => 'after',
'hooked' => array(
'woocommerce_template_loop_rating' => 5,
'woocommerce_template_loop_price' => 10,
),
),
'woocommerce_before_shop_loop_item' => array(
'block_name' => self::LOOP_ITEM_ID,
'position' => 'before',
'hooked' => array(
'block_names' => array( self::LOOP_ITEM_ID ),
'position' => 'before',
'hooked' => array(
'woocommerce_template_loop_product_link_open' => 10,
),
),
'woocommerce_after_shop_loop_item' => array(
'block_name' => self::LOOP_ITEM_ID,
'position' => 'after',
'hooked' => array(
'block_names' => array( self::LOOP_ITEM_ID ),
'position' => 'after',
'hooked' => array(
'woocommerce_template_loop_product_link_close' => 5,
'woocommerce_template_loop_add_to_cart' => 10,
),
),
'woocommerce_before_shop_loop' => array(
'block_name' => 'core/post-template',
'block_names' => array( 'core/post-template', 'woocommerce/product-template' ),
'position' => 'before',
'hooked' => array(
'woocommerce_output_all_notices' => 10,
@@ -249,7 +247,7 @@ class ArchiveProductTemplatesCompatibility extends AbstractTemplateCompatibility
),
),
'woocommerce_after_shop_loop' => array(
'block_name' => 'core/post-template',
'block_names' => array( 'core/post-template', 'woocommerce/product-template' ),
'position' => 'after',
'hooked' => array(
'woocommerce_pagination' => 10,
@@ -259,7 +257,7 @@ class ArchiveProductTemplatesCompatibility extends AbstractTemplateCompatibility
),
),
'woocommerce_no_products_found' => array(
'block_name' => 'core/query-no-results',
'block_names' => array( 'core/query-no-results' ),
'position' => 'before',
'hooked' => array(
'wc_no_products_found' => 10,
@@ -269,9 +267,9 @@ class ArchiveProductTemplatesCompatibility extends AbstractTemplateCompatibility
),
),
'woocommerce_archive_description' => array(
'block_name' => 'core/term-description',
'position' => 'before',
'hooked' => array(
'block_names' => array( 'core/term-description' ),
'position' => 'before',
'hooked' => array(
'woocommerce_taxonomy_archive_description' => 10,
'woocommerce_product_archive_description' => 10,
),
@@ -294,7 +292,7 @@ class ArchiveProductTemplatesCompatibility extends AbstractTemplateCompatibility
*/
private function inner_blocks_walker( &$block ) {
if (
$this->is_products_block_with_inherit_query( $block )
$this->is_products_block_with_inherit_query( $block ) || $this->is_product_collection_block_with_inherit_query( $block )
) {
$this->inject_attribute( $block );
$this->remove_default_hooks();
@@ -321,6 +319,69 @@ class ArchiveProductTemplatesCompatibility extends AbstractTemplateCompatibility
}
}
/**
* Check if block is within the product-query namespace
*
* @param array $block Parsed block data.
*/
private function is_block_within_namespace( $block ) {
$attributes = $block['attrs'];
return isset( $attributes['__woocommerceNamespace'] ) && 'woocommerce/product-query/product-template' === $attributes['__woocommerceNamespace'];
}
/**
* Check if block has isInherited attribute asigned
*
* @param array $block Parsed block data.
*/
private function is_block_inherited( $block ) {
$attributes = $block['attrs'];
$outcome = isset( $attributes['isInherited'] ) && 1 === $attributes['isInherited'];
return $outcome;
}
/**
* The core/post-template has two different block names:
* - core/post-template when the wrapper is rendered.
* - core/null when the loop item is rendered.
*
* @param array $block Parsed block data.
*/
private function is_null_post_template( $block ) {
$block_name = $block['blockName'];
return 'core/null' === $block_name && ( $this->is_block_inherited( $block ) || $this->is_block_within_namespace( $block ) );
}
/**
* Check if block is a Post template
*
* @param string $block_name Block name.
*/
private function is_post_template( $block_name ) {
return 'core/post-template' === $block_name;
}
/**
* Check if block is a Product Template
*
* @param string $block_name Block name.
*/
private function is_product_template( $block_name ) {
return 'woocommerce/product-template' === $block_name;
}
/**
* Check if block is eaither a Post template or Product Template
*
* @param string $block_name Block name.
*/
private function is_post_or_product_template( $block_name ) {
return $this->is_post_template( $block_name ) || $this->is_product_template( $block_name );
}
/**
* Check if the block is a Products block that inherits query from template.
@@ -335,6 +396,18 @@ class ArchiveProductTemplatesCompatibility extends AbstractTemplateCompatibility
$block['attrs']['query']['inherit'];
}
/**
* Check if the block is a Product Collection block that inherits query from template.
*
* @param array $block Parsed block data.
*/
private function is_product_collection_block_with_inherit_query( $block ) {
return 'woocommerce/product-collection' === $block['blockName'] &&
isset( $block['attrs']['query']['inherit'] ) &&
$block['attrs']['query']['inherit'];
}
/**
* Recursively inject the custom attribute to all nested blocks.
*

View File

@@ -1,6 +1,8 @@
<?php
namespace Automattic\WooCommerce\Blocks\Templates;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateMigrationUtils;
/**
* CartTemplate class.
*
@@ -13,7 +15,7 @@ class CartTemplate extends AbstractPageTemplate {
* @return string
*/
public static function get_slug() {
return 'cart';
return 'page-cart';
}
/**
@@ -21,7 +23,7 @@ class CartTemplate extends AbstractPageTemplate {
*
* @return \WP_Post|null Post object or null.
*/
public static function get_placeholder_page() {
protected function get_placeholder_page() {
$page_id = wc_get_page_id( 'cart' );
return $page_id ? get_post( $page_id ) : null;
}
@@ -32,17 +34,30 @@ class CartTemplate extends AbstractPageTemplate {
* @return boolean
*/
protected function is_active_template() {
if ( ! BlockTemplateMigrationUtils::has_migrated_page( 'cart' ) ) {
return false;
}
global $post;
$placeholder = $this->get_placeholder_page();
return null !== $placeholder && $post instanceof \WP_Post && $placeholder->post_name === $post->post_name;
}
/**
* Should return the title of the page.
* When the page should be displaying the template, add it to the hierarchy.
*
* @return string
* This places the template name e.g. `cart`, at the beginning of the template hierarchy array. The hook priority
* is 1 to ensure it runs first; other consumers e.g. extensions, could therefore inject their own template instead
* of this one when using the default priority of 10.
*
* @param array $templates Templates that match the pages_template_hierarchy.
*/
public static function get_template_title() {
return __( 'Cart', 'woocommerce' );
public function page_template_hierarchy( $templates ) {
if ( $this->is_active_template() ) {
array_unshift( $templates, $this->get_slug() );
array_unshift( $templates, 'cart' );
}
return $templates;
}
}

View File

@@ -1,6 +1,8 @@
<?php
namespace Automattic\WooCommerce\Blocks\Templates;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateMigrationUtils;
/**
* CheckoutTemplate class.
*
@@ -13,7 +15,7 @@ class CheckoutTemplate extends AbstractPageTemplate {
* @return string
*/
public static function get_slug() {
return 'checkout';
return 'page-checkout';
}
/**
@@ -21,28 +23,41 @@ class CheckoutTemplate extends AbstractPageTemplate {
*
* @return \WP_Post|null Post object or null.
*/
public static function get_placeholder_page() {
protected function get_placeholder_page() {
$page_id = wc_get_page_id( 'checkout' );
return $page_id ? get_post( $page_id ) : null;
}
/**
* Should return the title of the page.
*
* @return string
*/
public static function get_template_title() {
return __( 'Checkout', 'woocommerce' );
}
/**
* True when viewing the checkout page or checkout endpoint.
*
* @return boolean
*/
public function is_active_template() {
protected function is_active_template() {
if ( ! BlockTemplateMigrationUtils::has_migrated_page( 'checkout' ) ) {
return false;
}
global $post;
$placeholder = $this->get_placeholder_page();
return null !== $placeholder && $post instanceof \WP_Post && $placeholder->post_name === $post->post_name;
}
/**
* When the page should be displaying the template, add it to the hierarchy.
*
* This places the template name e.g. `cart`, at the beginning of the template hierarchy array. The hook priority
* is 1 to ensure it runs first; other consumers e.g. extensions, could therefore inject their own template instead
* of this one when using the default priority of 10.
*
* @param array $templates Templates that match the pages_template_hierarchy.
*/
public function page_template_hierarchy( $templates ) {
if ( $this->is_active_template() ) {
array_unshift( $templates, $this->get_slug() );
array_unshift( $templates, 'checkout' );
}
return $templates;
}
}

View File

@@ -60,7 +60,7 @@ class ClassicTemplatesCompatibility {
global $pagenow;
if ( is_shop() || is_product_taxonomy() || 'widgets.php' === $pagenow ) {
$this->asset_data_registry->add( 'has_filterable_products', true, true );
$this->asset_data_registry->add( 'hasFilterableProducts', true, true );
}
}
@@ -75,7 +75,7 @@ class ClassicTemplatesCompatibility {
*/
public function set_php_template_data() {
if ( is_shop() || is_product_taxonomy() ) {
$this->asset_data_registry->add( 'is_rendering_php_template', true, true );
$this->asset_data_registry->add( 'isRenderingPhpTemplate', true, true );
}
}
}

View File

@@ -16,12 +16,30 @@ class OrderConfirmationTemplate extends AbstractPageTemplate {
return 'order-confirmation';
}
/**
* Initialization method.
*/
protected function init() {
parent::init();
add_action( 'wp_before_admin_bar_render', array( $this, 'remove_edit_page_link' ) );
}
/**
* Remove edit page from admin bar.
*/
public function remove_edit_page_link() {
if ( $this->is_active_template() ) {
global $wp_admin_bar;
$wp_admin_bar->remove_menu( 'edit' );
}
}
/**
* Returns the page object assigned to this template/page.
*
* @return \WP_Post|null Post object or null.
*/
public static function get_placeholder_page() {
protected function get_placeholder_page() {
return null;
}

View File

@@ -0,0 +1,120 @@
<?php
namespace Automattic\WooCommerce\Blocks\Templates;
/**
* SingleProductTemplae class.
*
* @internal
*/
class SingleProductTemplate {
/**
* Replace the first single product template block with the password form. Remove all other single product template blocks.
*
* @param array $parsed_blocks Array of parsed block objects.
* @param boolean $is_already_replaced If the password form has already been added.
* @return array Parsed blocks
*/
private static function replace_first_single_product_template_block_with_password_form( $parsed_blocks, $is_already_replaced ) {
// We want to replace the first single product template block with the password form. We also want to remove all other single product template blocks.
// This array doesn't contains all the blocks. For example, it missing the breadcrumbs blocks: it doesn't make sense replace the breadcrumbs with the password form.
$single_product_template_blocks = array( 'woocommerce/product-image-gallery', 'woocommerce/product-details', 'woocommerce/add-to-cart-form', 'woocommerce/product-meta', 'woocommerce/product-rating', 'woocommerce/product-price', 'woocommerce/related-products' );
return array_reduce(
$parsed_blocks,
function( $carry, $block ) use ( $single_product_template_blocks ) {
if ( in_array( $block['blockName'], $single_product_template_blocks, true ) ) {
if ( $carry['is_already_replaced'] ) {
return array(
'blocks' => $carry['blocks'],
'html_block' => null,
'removed' => true,
'is_already_replaced' => true,
);
}
return array(
'blocks' => $carry['blocks'],
'html_block' => parse_blocks( '<!-- wp:html -->' . get_the_password_form() . '<!-- /wp:html -->' )[0],
'removed' => false,
'is_already_replaced' => $carry['is_already_replaced'],
);
}
if ( isset( $block['innerBlocks'] ) && count( $block['innerBlocks'] ) > 0 ) {
$index = 0;
$new_inner_blocks = array();
$new_inner_contents = $block['innerContent'];
foreach ( $block['innerContent'] as $inner_content ) {
// Don't process the closing tag of the block.
if ( count( $block['innerBlocks'] ) === $index ) {
break;
}
$blocks = self::replace_first_single_product_template_block_with_password_form( array( $block['innerBlocks'][ $index ] ), $carry['is_already_replaced'] );
$new_blocks = $blocks['blocks'];
$html_block = $blocks['html_block'];
$is_removed = $blocks['removed'];
$carry['is_already_replaced'] = $blocks['is_already_replaced'];
if ( isset( $html_block ) ) {
$new_inner_blocks = array_merge( $new_inner_blocks, $new_blocks, array( $html_block ) );
$carry['is_already_replaced'] = true;
} else {
$new_inner_blocks = array_merge( $new_inner_blocks, $new_blocks );
}
if ( $is_removed ) {
unset( $new_inner_contents[ $index ] );
// The last element of the inner contents contains the closing tag of the block. We don't want to remove it.
if ( $index + 1 < count( $new_inner_contents ) ) {
unset( $new_inner_contents[ $index + 1 ] );
}
$new_inner_contents = array_values( $new_inner_contents );
}
$index++;
}
$block['innerBlocks'] = $new_inner_blocks;
$block['innerContent'] = $new_inner_contents;
return array(
'blocks' => array_merge( $carry['blocks'], array( $block ) ),
'html_block' => null,
'removed' => false,
'is_already_replaced' => $carry['is_already_replaced'],
);
}
return array(
'blocks' => array_merge( $carry['blocks'], array( $block ) ),
'html_block' => null,
'removed' => false,
'is_already_replaced' => $carry['is_already_replaced'],
);
},
array(
'blocks' => array(),
'html_block' => null,
'removed' => false,
'is_already_replaced' => $is_already_replaced,
)
);
}
/**
* Add password form to the Single Product Template.
*
* @param string $content The content of the template.
* @return string
*/
public static function add_password_form( $content ) {
$parsed_blocks = parse_blocks( $content );
$blocks = self::replace_first_single_product_template_block_with_password_form( $parsed_blocks, false );
$serialized_blocks = serialize_blocks( $blocks['blocks'] );
return $serialized_blocks;
}
}

View File

@@ -32,7 +32,7 @@ class SingleProductTemplateCompatibility extends AbstractTemplateCompatibility {
$block_hooks = array_filter(
$this->hook_data,
function( $hook ) use ( $block_name ) {
return $hook['block_name'] === $block_name;
return in_array( $block_name, $hook['block_names'], true );
}
);
@@ -170,46 +170,46 @@ class SingleProductTemplateCompatibility extends AbstractTemplateCompatibility {
protected function set_hook_data() {
$this->hook_data = array(
'woocommerce_before_main_content' => array(
'block_name' => '',
'position' => 'before',
'hooked' => array(
'block_names' => array(),
'position' => 'before',
'hooked' => array(
'woocommerce_output_content_wrapper' => 10,
'woocommerce_breadcrumb' => 20,
),
),
'woocommerce_after_main_content' => array(
'block_name' => '',
'position' => 'after',
'hooked' => array(
'block_names' => array(),
'position' => 'after',
'hooked' => array(
'woocommerce_output_content_wrapper_end' => 10,
),
),
'woocommerce_sidebar' => array(
'block_name' => '',
'position' => 'after',
'hooked' => array(
'block_names' => array(),
'position' => 'after',
'hooked' => array(
'woocommerce_get_sidebar' => 10,
),
),
'woocommerce_before_single_product' => array(
'block_name' => '',
'position' => 'before',
'hooked' => array(
'block_names' => array(),
'position' => 'before',
'hooked' => array(
'woocommerce_output_all_notices' => 10,
),
),
'woocommerce_before_single_product_summary' => array(
'block_name' => '',
'position' => 'before',
'hooked' => array(
'block_names' => array(),
'position' => 'before',
'hooked' => array(
'woocommerce_show_product_sale_flash' => 10,
'woocommerce_show_product_images' => 20,
),
),
'woocommerce_single_product_summary' => array(
'block_name' => '',
'position' => 'before',
'hooked' => array(
'block_names' => array(),
'position' => 'before',
'hooked' => array(
'woocommerce_template_single_title' => 5,
'woocommerce_template_single_rating' => 10,
'woocommerce_template_single_price' => 10,
@@ -220,29 +220,29 @@ class SingleProductTemplateCompatibility extends AbstractTemplateCompatibility {
),
),
'woocommerce_after_single_product' => array(
'block_name' => '',
'position' => 'after',
'hooked' => array(),
'block_names' => array(),
'position' => 'after',
'hooked' => array(),
),
'woocommerce_product_meta_start' => array(
'block_name' => 'woocommerce/product-meta',
'position' => 'before',
'hooked' => array(),
'block_names' => array( 'woocommerce/product-meta' ),
'position' => 'before',
'hooked' => array(),
),
'woocommerce_product_meta_end' => array(
'block_name' => 'woocommerce/product-meta',
'position' => 'after',
'hooked' => array(),
'block_names' => array( 'woocommerce/product-meta' ),
'position' => 'after',
'hooked' => array(),
),
'woocommerce_share' => array(
'block_name' => 'woocommerce/product-details',
'position' => 'before',
'hooked' => array(),
'block_names' => array( 'woocommerce/product-details' ),
'position' => 'before',
'hooked' => array(),
),
'woocommerce_after_single_product_summary' => array(
'block_name' => 'woocommerce/product-details',
'position' => 'after',
'hooked' => array(
'block_names' => array( 'woocommerce/product-details' ),
'position' => 'after',
'hooked' => array(
'woocommerce_output_product_data_tabs' => 10,
// We want to display the upsell products after the last block that belongs to the Single Product.
// 'woocommerce_upsell_display' => 15.
@@ -269,7 +269,6 @@ class SingleProductTemplateCompatibility extends AbstractTemplateCompatibility {
$wrapped_blocks = self::wrap_single_product_template( $template_content );
$template = self::inject_custom_attributes_to_first_and_last_block_single_product_template( $wrapped_blocks );
return self::serialize_blocks( $template );
}
/**