From e6b1cac49c0d252df930425c7936b12e38bb2a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Mon, 26 Aug 2024 09:46:32 +0200 Subject: [PATCH] Update compatibility layer logic so it detects blocks inside patterns (#50595) * Detect Legacy Template block when it's inside a pattern * Detect Single Product blocks when they are inside a pattern * Typo * Remove empty error messages * Fix wrong variable passed to parse_blocks() * Remove unnecessary parameters * Add tests to check if the Single Product template contents are updated when the Legacy Template is in the content * Add changelog file * Linting * Typo * Make sure the correct template is used when deciding whether to disable the compatibility layer or not * Simplify code * Remove duplicate content in tests * Simplify single product slug logic * Add an extra test to make sure Single Product template logic doesn't leak into other templates * Linting --------- Co-authored-by: Sam Seay --- .../fix-50055-compatibility-layer-patterns | 4 + .../AbstractTemplateCompatibility.php | 4 +- .../Templates/SingleProductTemplate.php | 32 ++- .../SingleProductTemplateCompatibility.php | 30 +-- .../src/Blocks/Utils/BlockTemplateUtils.php | 41 +++- ...ingleProductTemplateCompatibilityTests.php | 106 ++++++-- .../Templates/SingleProductTemplateTests.php | 226 ++++++++++++++++-- 7 files changed, 376 insertions(+), 67 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-50055-compatibility-layer-patterns diff --git a/plugins/woocommerce/changelog/fix-50055-compatibility-layer-patterns b/plugins/woocommerce/changelog/fix-50055-compatibility-layer-patterns new file mode 100644 index 00000000000..e6811df2b13 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-50055-compatibility-layer-patterns @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Update the logic that conditionally activates the compatibility layer in WooCommerce block templates so it detects blocks inside patterns diff --git a/plugins/woocommerce/src/Blocks/Templates/AbstractTemplateCompatibility.php b/plugins/woocommerce/src/Blocks/Templates/AbstractTemplateCompatibility.php index 3d622a345c2..b06892291c3 100644 --- a/plugins/woocommerce/src/Blocks/Templates/AbstractTemplateCompatibility.php +++ b/plugins/woocommerce/src/Blocks/Templates/AbstractTemplateCompatibility.php @@ -61,9 +61,9 @@ abstract class AbstractTemplateCompatibility { * @since 7.6.0 * @param boolean. */ - $is_disabled_compatility_layer = apply_filters( 'woocommerce_disable_compatibility_layer', false ); + $is_disabled_compatibility_layer = apply_filters( 'woocommerce_disable_compatibility_layer', false ); - if ( $is_disabled_compatility_layer ) { + if ( $is_disabled_compatibility_layer ) { return $block_content; } diff --git a/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplate.php b/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplate.php index 942f807422f..69ef307fc3a 100644 --- a/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplate.php +++ b/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplate.php @@ -23,7 +23,7 @@ class SingleProductTemplate extends AbstractTemplate { */ public function init() { add_action( 'template_redirect', array( $this, 'render_block_template' ) ); - add_filter( 'get_block_templates', array( $this, 'update_single_product_content' ), 11, 3 ); + add_filter( 'get_block_templates', array( $this, 'update_single_product_content' ), 11, 1 ); } /** @@ -51,13 +51,31 @@ class SingleProductTemplate extends AbstractTemplate { if ( ! is_embed() && is_singular( 'product' ) ) { global $post; - $valid_slugs = array( self::SLUG ); - if ( 'product' === $post->post_type && $post->post_name ) { + $valid_slugs = array( self::SLUG ); + $single_product_slug = 'product' === $post->post_type && $post->post_name ? 'single-product-' . $post->post_name : ''; + if ( $single_product_slug ) { $valid_slugs[] = 'single-product-' . $post->post_name; } $templates = get_block_templates( array( 'slug__in' => $valid_slugs ) ); - if ( isset( $templates[0] ) && BlockTemplateUtils::template_has_legacy_template_block( $templates[0] ) ) { + if ( count( $templates ) === 0 ) { + return; + } + + // Use the first template by default. + $template = $templates[0]; + + // Check if there is a template matching the slug `single-product-{post_name}`. + if ( count( $valid_slugs ) > 1 && count( $templates ) > 1 ) { + foreach ( $templates as $t ) { + if ( $single_product_slug === $t->slug ) { + $template = $t; + break; + } + } + } + + if ( isset( $template ) && BlockTemplateUtils::template_has_legacy_template_block( $template ) ) { add_filter( 'woocommerce_disable_compatibility_layer', '__return_true' ); } @@ -68,12 +86,10 @@ class SingleProductTemplate extends AbstractTemplate { /** * Add the block template objects to be used. * - * @param array $query_result Array of template objects. - * @param array $query Optional. Arguments to retrieve templates. - * @param string $template_type wp_template or wp_template_part. + * @param array $query_result Array of template objects. * @return array */ - public function update_single_product_content( $query_result, $query, $template_type ) { + public function update_single_product_content( $query_result ) { $query_result = array_map( function ( $template ) { if ( str_contains( $template->slug, self::SLUG ) ) { diff --git a/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplateCompatibility.php b/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplateCompatibility.php index 05191bcbdbb..f48d7697798 100644 --- a/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplateCompatibility.php +++ b/plugins/woocommerce/src/Blocks/Templates/SingleProductTemplateCompatibility.php @@ -1,6 +1,8 @@ get_registered( $block['attrs']['slug'] ); + $pattern_blocks = parse_blocks( $pattern['content'] ); + + if ( self::has_block_including_patterns( $block_names, $pattern_blocks ) ) { + return true; + } + } + } + + return false; + } + /** * Returns whether the passed `$template` has the legacy template block. * @@ -703,7 +736,13 @@ class BlockTemplateUtils { * @return boolean */ public static function template_has_legacy_template_block( $template ) { - return has_block( 'woocommerce/legacy-template', $template->content ); + if ( has_block( 'woocommerce/legacy-template', $template->content ) ) { + return true; + } + + $blocks = parse_blocks( $template->content ); + + return self::has_block_including_patterns( array( 'woocommerce/legacy-template' ), $blocks ); } /** diff --git a/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateCompatibilityTests.php b/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateCompatibilityTests.php index 4ab7388ed9c..e67d08b5563 100644 --- a/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateCompatibilityTests.php +++ b/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateCompatibilityTests.php @@ -37,10 +37,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -72,10 +72,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -155,10 +155,80 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); + } + + /** + * Test that the Single Product Template is wrapped in a div with the correct class if it contains a pattern that contains a block related to the Single Product Template. + */ + public function test_add_compatibility_layer_if_contains_pattern_with_single_product_blocks() { + register_block_pattern( + 'test-pattern', + array( + 'title' => 'Test Pattern', + 'description' => 'Test Pattern Description', + 'content' => '', + ) + ); + + $default_single_product_template = ' + + + '; + + $expected_single_product_template = ' + + +
+ +
+ + '; + + $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); + + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); + $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); + + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); + } + + /** + * Test that the Single Product Template is wrapped in a div with the correct class if it contains a pattern that contains an inner block related to the Single Product Template. + */ + public function test_add_compatibility_layer_if_contains_pattern_with_inner_single_product_blocks() { + register_block_pattern( + 'test-pattern', + array( + 'title' => 'Test Pattern', + 'description' => 'Test Pattern Description', + 'content' => '
', + ) + ); + + $default_single_product_template = ' + + + '; + + $expected_single_product_template = ' + + +
+ +
+ + '; + + $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); + + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); + $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); + + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -222,10 +292,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -251,10 +321,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } @@ -281,10 +351,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -322,10 +392,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -359,10 +429,10 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } /** @@ -398,9 +468,9 @@ class SingleProductTemplateCompatibilityTests extends WP_UnitTestCase { $result = SingleProductTemplateCompatibility::add_compatibility_layer( $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', $expected_single_product_template ); - $this->assertEquals( $result_without_withespace, $expected_single_product_template_without_whitespace, '' ); + $this->assertEquals( $result_without_whitespace, $expected_single_product_template_without_whitespace, '' ); } } diff --git a/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateTests.php b/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateTests.php index 7649173e24a..634df6d181c 100644 --- a/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateTests.php +++ b/plugins/woocommerce/tests/php/src/Blocks/Templates/SingleProductTemplateTests.php @@ -11,6 +11,203 @@ use \WP_UnitTestCase; */ class SingleProductTemplateTests extends WP_UnitTestCase { + /** + * Test that the Product Catalog template content isn't updated mistakenly. + * In other words, make sure the Single Product template logic doesn't leak + * into other templates. + * + */ + public function test_dont_update_single_product_content_for_other_templates() { + $single_product_template = new SingleProductTemplate(); + $default_product_catalog_template_content = ' + + + '; + + $template = new \WP_Block_Template(); + $template->slug = 'archive-product'; + $template->title = 'Product Catalog'; + $template->content = $default_product_catalog_template_content; + $template->type = 'wp_template'; + + $result = $single_product_template->update_single_product_content( + array( + $template, + ), + ); + + $this->assertEquals( + $default_product_catalog_template_content, + $result[0]->content + ); + } + + /** + * Test that the Single Product template content isn't updated if it + * contains the Legacy Template block. + * + */ + public function test_dont_update_single_product_content_with_legacy_template() { + $single_product_template = new SingleProductTemplate(); + $default_single_product_template_content = ' + + + '; + + $template = new \WP_Block_Template(); + $template->slug = 'single-product'; + $template->title = 'Single Product'; + $template->content = $default_single_product_template_content; + $template->type = 'wp_template'; + + $result = $single_product_template->update_single_product_content( + array( + $template, + ), + ); + + $this->assertEquals( + $default_single_product_template_content, + $result[0]->content + ); + } + + /** + * Test that the Single Product template content is updated if it doesn't + * contain the Legacy Template block. + * + */ + public function test_update_single_product_content_with_legacy_template() { + $single_product_template = new SingleProductTemplate(); + $default_single_product_template_content = ' + + + '; + $expected_single_product_template_content = ' + + +
+ +
+ + '; + + $template = new \WP_Block_Template(); + $template->slug = 'single-product'; + $template->title = 'Single Product'; + $template->content = $default_single_product_template_content; + $template->type = 'wp_template'; + + $result = $single_product_template->update_single_product_content( + array( + $template, + ), + ); + + $expected_single_product_template_without_whitespace = preg_replace( + '/\s+/', + '', + $expected_single_product_template_content + ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result[0]->content ); + + $this->assertEquals( + $expected_single_product_template_without_whitespace, + $result_without_whitespace + ); + } + + /** + * Test that the Single Product template content isn't updated if it + * contains a pattern with the Legacy Template block. + * + */ + public function test_dont_update_single_product_content_with_legacy_template_inside_a_pattern() { + register_block_pattern( + 'test-pattern', + array( + 'title' => 'Test Pattern', + 'description' => 'Test Pattern Description', + 'content' => '', + ) + ); + $single_product_template = new SingleProductTemplate(); + $default_single_product_template_content = ' + + + '; + + $template = new \WP_Block_Template(); + $template->slug = 'single-product'; + $template->title = 'Single Product'; + $template->content = $default_single_product_template_content; + $template->type = 'wp_template'; + + $result = $single_product_template->update_single_product_content( + array( + $template, + ), + ); + + $this->assertEquals( + $default_single_product_template_content, + $result[0]->content + ); + } + + /** + * Test that the Single Product template content is updated if it doesn't + * contain the Legacy Template block. + * + */ + public function test_update_single_product_content_with_legacy_template_inside_a_pattern() { + register_block_pattern( + 'test-pattern', + array( + 'title' => 'Test Pattern', + 'description' => 'Test Pattern Description', + 'content' => '', + ) + ); + $single_product_template = new SingleProductTemplate(); + $default_single_product_template_content = ' + + + '; + $expected_single_product_template_content = ' + + +
+ +
+ + '; + + $template = new \WP_Block_Template(); + $template->slug = 'single-product'; + $template->title = 'Single Product'; + $template->content = $default_single_product_template_content; + $template->type = 'wp_template'; + + $result = $single_product_template->update_single_product_content( + array( + $template, + ), + ); + + $expected_single_product_template_without_whitespace = preg_replace( + '/\s+/', + '', + $expected_single_product_template_content + ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result[0]->content ); + + $this->assertEquals( + $expected_single_product_template_without_whitespace, + $result_without_whitespace + ); + } + /** * Test that the password form isn't added to the Single Product Template. * @@ -38,7 +235,7 @@ class SingleProductTemplateTests extends WP_UnitTestCase { $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); $expected_single_product_template_without_whitespace = preg_replace( '/\s+/', '', @@ -46,9 +243,8 @@ class SingleProductTemplateTests extends WP_UnitTestCase { ); $this->assertEquals( - $result_without_withespace, - $expected_single_product_template_without_whitespace, - '' + $result_without_whitespace, + $expected_single_product_template_without_whitespace ); } @@ -81,11 +277,11 @@ class SingleProductTemplateTests extends WP_UnitTestCase { $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); - $result_without_withespace_without_custom_pwbox_ids = preg_replace( + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace_without_custom_pwbox_ids = preg_replace( '/pwbox-\d+/', '', - $result_without_withespace + $result_without_whitespace ); $expected_single_product_template_without_whitespace = preg_replace( @@ -101,9 +297,8 @@ class SingleProductTemplateTests extends WP_UnitTestCase { ); $this->assertEquals( - $result_without_withespace_without_custom_pwbox_ids, - $expected_single_product_template_without_whitespace_without_custom_pwbox_ids, - '' + $result_without_whitespace_without_custom_pwbox_ids, + $expected_single_product_template_without_whitespace_without_custom_pwbox_ids ); } @@ -219,11 +414,11 @@ class SingleProductTemplateTests extends WP_UnitTestCase { $default_single_product_template ); - $result_without_withespace = preg_replace( '/\s+/', '', $result ); - $result_without_withespace_without_custom_pwbox_ids = preg_replace( + $result_without_whitespace = preg_replace( '/\s+/', '', $result ); + $result_without_whitespace_without_custom_pwbox_ids = preg_replace( '/pwbox-\d+/', '', - $result_without_withespace + $result_without_whitespace ); $expected_single_product_template_without_whitespace = preg_replace( @@ -239,9 +434,8 @@ class SingleProductTemplateTests extends WP_UnitTestCase { ); $this->assertEquals( - $result_without_withespace_without_custom_pwbox_ids, - $expected_single_product_template_without_whitespace_without_custom_pwbox_ids, - '' + $result_without_whitespace_without_custom_pwbox_ids, + $expected_single_product_template_without_whitespace_without_custom_pwbox_ids ); } }