n self::serialize_blocks( $template ); } $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 ); } /** * 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 array Wrapped template content inside a div. */ private static function wrap_single_product_template( $template_content ) { $parsed_blocks = parse_blocks( $template_content ); $grouped_blocks = self::group_blocks( $parsed_blocks ); $wrapped_blocks = array_map( function( $blocks ) { if ( 'core/template-part' === $blocks[0]['blockName'] ) { return $blocks; } $has_single_product_template_blocks = self::has_single_product_template_blocks( $blocks ); if ( $has_single_product_template_blocks ) { $wrapped_block = self::create_wrap_block_group( $blocks ); return array( $wrapped_block[0] ); } return $blocks; }, $grouped_blocks ); return $wrapped_blocks; } /** * Add custom attributes to the first group block and last group block that wrap Single Product Template blocks. * * @param array $wrapped_blocks Wrapped blocks. * @return array */ private static function inject_custom_attributes_to_first_and_last_block_single_product_template( $wrapped_blocks ) { $template_with_custom_attributes = array_reduce( $wrapped_blocks, function( $carry, $item ) { $index = $carry['index']; $carry['index'] = $carry['index'] + 1; // If the block is a child of a group block, we need to get the first block of the group. $block = isset( $item[0] ) ? $item[0] : $item; if ( 'core/template-part' === $block['blockName'] || self::is_custom_html( $block ) ) { $carry['template'][] = $block; return $carry; } if ( '' === $carry['first_block']['index'] ) { $block['attrs'][ self::IS_FIRST_BLOCK ] = true; $carry['first_block']['index'] = $index; } if ( '' !== $carry['last_block']['index'] ) { $index_element = $carry['last_block']['index']; $carry['last_block']['index'] = $index; $block['attrs'][ self::IS_LAST_BLOCK ] = true; unset( $carry['template'][ $index_element ]['attrs'][ self::IS_LAST_BLOCK ] ); $carry['template'][] = $block; return $carry; } $block['attrs'][ self::IS_LAST_BLOCK ] = true; $carry['last_block']['index'] = $index; $carry['template'][] = $block; return $carry; }, array( 'template' => array(), 'first_block' => array( 'index' => '', ), 'last_block' => array( 'index' => '', ), 'index' => 0, ) ); return array( $template_with_custom_attributes['template'] ); } /** * Wrap all the blocks inside the template in a group block. * * @param array $blocks Array of parsed block objects. * @return array Group block with the blocks inside. */ private static function create_wrap_block_group( $blocks ) { $serialized_blocks = serialize_blocks( $blocks ); $new_block = parse_blocks( sprintf( '
%1$s
', $serialized_blocks ) ); $new_block['innerBlocks'] = $blocks; return $new_block; } /** * Check if the Single Product template has a single product template block: * woocommerce/product-gallery-image, woocommerce/product-details, woocommerce/add-to-cart-form] * * @param array $parsed_blocks Array of parsed block objects. * @return bool True if the template has a single product template block, false otherwise. */ private static function has_single_product_template_blocks( $parsed_blocks ) { $single_product_template_blocks = array( 'woocommerce/product-image-gallery', 'woocommerce/product-details', 'woocommerce/add-to-cart-form', 'woocommerce/product-meta', 'woocommerce/product-price', 'woocommerce/breadcrumbs' ); $found = false; foreach ( $parsed_blocks as $block ) { if ( isset( $block['blockName'] ) && in_array( $block['blockName'], $single_product_template_blocks, true ) ) { $found = true; break; } $found = self::has_single_product_template_blocks( $block['innerBlocks'], $single_product_template_blocks ); if ( $found ) { break; } } return $found; } /** * Group blocks in this way: * B1 + TP1 + B2 + B3 + B4 + TP2 + B5 * (B = Block, TP = Template Part) * becomes: * [[B1], [TP1], [B2, B3, B4], [TP2], [B5]] * * @param array $parsed_blocks Array of parsed block objects. * @return array Array of blocks grouped by template part. */ private static function group_blocks( $parsed_blocks ) { return array_reduce( $parsed_blocks, function( array $carry, array $block ) { if ( 'core/template-part' === $block['blockName'] ) { $carry[] = array( $block ); return $carry; } $last_element_index = count( $carry ) - 1; if ( isset( $carry[ $last_element_index ][0]['blockName'] ) && 'core/template-part' !== $carry[ $last_element_index ][0]['blockName'] ) { $carry[ $last_element_index ][] = $block; return $carry; } $carry[] = array( $block ); return $carry; }, array() ); } /** * Inject the hooks after the div wrapper. * * @param string $block_content Block Content. * @param array $hooks Hooks to inject. * @return array */ private function inject_hooks_after_the_wrapper( $block_content, $hooks ) { $closing_tag_position = strpos( $block_content, '>' ); return substr_replace( $block_content, $this->get_hooks_buffer( $hooks, 'before' ), // Add 1 to the position to inject the content after the closing tag. $closing_tag_position + 1, 0 ); } /** * Plain custom HTML block is parsed as block with an empty blockName with a filled innerHTML. * * @param array $block Parse block. * @return bool */ private static function is_custom_html( $block ) { return empty( $block['blockName'] ) && ! empty( $block['innerHTML'] ); } /** * Serialize template. * * @param array $parsed_blocks Parsed blocks. * @return string */ private static function serialize_blocks( $parsed_blocks ) { return array_reduce( $parsed_blocks, function( $carry, $item ) { if ( is_array( $item ) ) { return $carry . serialize_blocks( $item ); } return $carry . serialize_block( $item ); }, '' ); } }
Fatal error: Uncaught Error: Class 'Automattic\WooCommerce\Blocks\Templates\SingleProductTemplateCompatibility' not found in /home/arasetne/public_html/wp-content/plugins/woocommerce/packages/woocommerce-blocks/src/Domain/Bootstrap.php:345 Stack trace: #0 /home/arasetne/public_html/wp-content/plugins/woocommerce/packages/woocommerce-blocks/src/Registry/AbstractDependencyType.php(42): Automattic\WooCommerce\Blocks\Domain\Bootstrap->Automattic\WooCommerce\Blocks\Domain\{closure}(Object(Automattic\WooCommerce\Blocks\Registry\Container)) #1 /home/arasetne/public_html/wp-content/plugins/woocommerce/packages/woocommerce-blocks/src/Registry/SharedType.php(28): Automattic\WooCommerce\Blocks\Registry\AbstractDependencyType->resolve_value(Object(Automattic\WooCommerce\Blocks\Registry\Container)) #2 /home/arasetne/public_html/wp-content/plugins/woocommerce/packages/woocommerce-blocks/src/Registry/Container.php(96): Automattic\WooCommerce\Blocks\Registry\SharedType->get(Object(Automattic\WooCommerce\Blocks\Registry\Container)) #3 /ho in /home/arasetne/public_html/wp-content/plugins/woocommerce/packages/woocommerce-blocks/src/Domain/Bootstrap.php on line 345