Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Wrap the Single Product Template in a div with the product class #8364

Merged
8 changes: 8 additions & 0 deletions src/BlockTemplatesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
namespace Automattic\WooCommerce\Blocks;

use Automattic\WooCommerce\Blocks\Domain\Package;
use Automattic\WooCommerce\Blocks\Templates\BlockTemplatesCompatibility;
use Automattic\WooCommerce\Blocks\Templates\ProductAttributeTemplate;
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils;

Expand Down Expand Up @@ -322,6 +323,13 @@ function( $template ) {
if ( ! $template->description ) {
$template->description = BlockTemplateUtils::get_block_template_description( $template->slug );
}

if ( 'single-product' === $template->slug ) {
$new_content = BlockTemplatesCompatibility::wrap_single_product_template( $template->content );
$template->content = $new_content;
return $template;
}

return $template;
},
$query_result
Expand Down
64 changes: 64 additions & 0 deletions src/Templates/BlockTemplatesCompatibility.php
Original file line number Diff line number Diff line change
Expand Up @@ -361,4 +361,68 @@ protected function inject_attribute( &$block ) {
}
}

/**
* For compatibility reason, we need to wrap the Single Product template in a div with specific class.
* For more details, see https://github.com/woocommerce/woocommerce-blocks/issues/8314.
*
* @param string $template_content Template Content.
* @return string Wrapped template content inside a div.
*/
public static function wrap_single_product_template( $template_content ) {
$parsed_blocks = parse_blocks( $template_content );
$last_template_parts_before_template_index = self::find_first_block( $parsed_blocks );

$wrap_block_group = self::create_wrap_block_group(
$parsed_blocks[ $last_template_parts_before_template_index ]
);

$parsed_blocks[ $last_template_parts_before_template_index ] = $wrap_block_group[0];

return serialize_blocks( $parsed_blocks );
}

/**
* Find the first block that is not a template part.
*
* @param array $parsed_blocks Array of parsed block objects.
*/
private static function find_first_block( $parsed_blocks ) {
$last_template_parts_before_template = null;
foreach ( $parsed_blocks as $key => $value ) {
if ( 'core/template-part' === $value['blockName'] || empty( $value['blockName'] ) ) {
continue;
}

$last_template_parts_before_template = $key;
break;
}
return $last_template_parts_before_template;
}

/**
* Wrap all the blocks inside the template in a group block.
*
* @param array $inner_blocks Array of parsed block objects.
* @return array Group block with the inner blocks.
*/
private static function create_wrap_block_group( $inner_blocks ) {
$serialized_blocks = serialize_block( $inner_blocks );

$new_block = parse_blocks(
sprintf(
'<!-- wp:group {"className":"woocommerce product"} -->
<div class="wp-block-group woocommerce product">
%1$s
</div>
<!-- /wp:group -->',
Comment on lines +420 to +424
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong opinion, but I'm curious to know why you defined a Group block instead of simply a div?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using parse_blocks function to generate the new structure. In the WordPress template markup, the div is represented with a block group. This is the reason I decided to define a Group block.

$serialized_blocks
)
);

$new_block['innerBlocks'] = $inner_blocks;

return $new_block;

}

}
48 changes: 48 additions & 0 deletions tests/php/Templates/BlockTemplatesCompatibilityTests.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace Automattic\WooCommerce\Blocks\Tests\Templates;

use \WP_UnitTestCase;
use Automattic\WooCommerce\Blocks\Templates\BlockTemplatesCompatibility;

/**
* Tests the BlockTemplatesCompatibility class
*
*/
class BlockTemplatesCompatibilityTests extends WP_UnitTestCase {

/**
* Test that the default Single Product Template is wrapped in a div with the correct class.
*/
public function test_wrap_single_product_template_with_default_single_product_template() {

$default_single_product_template = '
<!-- wp:template-part {"slug":"header","theme":"twentytwentythree","tagName":"header"} /-->
<!-- wp:group {"layout":{"inherit":true,"type":"constrained"}} -->
<div class="wp-block-group">
<!-- wp:woocommerce/legacy-template {"template":"single-product"} /-->
</div>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer","theme":"twentytwentythree","tagName":"footer"} /-->';

$expected_single_product_template = '
<!-- wp:template-part {"slug":"header","theme":"twentytwentythree","tagName":"header"} /-->
<!-- wp:group {"className":"woocommerce product"} -->
<div class="wp-block-group woocommerce product">
<!-- wp:group {"layout":{"inherit":true,"type":"constrained"}} -->
<div class="wp-block-group">
<!-- wp:woocommerce/legacy-template {"template":"single-product"} /-->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer","theme":"twentytwentythree","tagName":"footer"} /-->';

$result = BlockTemplatesCompatibility::wrap_single_product_template( $default_single_product_template );

$result_without_withespace = 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, '' );
}
}