forked from woocommerce/woocommerce-blocks
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
BlockTemplateController (woocommerce#4981)
* BlockTemplateController * Check if theme already has template * ThemeUtils file to check for FSE enabled themes * Use Gutenberg global gutenberg_supports_block_templates * Remove ThemeUtils reference * Update with code review comments * Delete ThemeUtils and move supports_block_templates check * Duplicate functions from Gutenberg into Utils file * Remove template file * Check template directory and stylesheet directory for template
- Loading branch information
1 parent
87a1149
commit 78d8a1f
Showing
3 changed files
with
249 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
<?php | ||
namespace Automattic\WooCommerce\Blocks; | ||
|
||
use Automattic\WooCommerce\Blocks\Utils\BlockTemplateUtils; | ||
|
||
/** | ||
* BlockTypesController class. | ||
* | ||
* @internal | ||
*/ | ||
class BlockTemplatesController { | ||
|
||
/** | ||
* Holds the path for the directory where the block templates will be kept. | ||
* | ||
* @var string | ||
*/ | ||
private $templates_directory; | ||
|
||
/** | ||
* Directory name of the block template directory. | ||
* | ||
* @var string | ||
*/ | ||
const TEMPLATES_DIR_NAME = 'block-templates'; | ||
|
||
/** | ||
* Constructor. | ||
*/ | ||
public function __construct() { | ||
$this->templates_directory = plugin_dir_path( __DIR__ ) . 'templates/' . self::TEMPLATES_DIR_NAME; | ||
$this->init(); | ||
} | ||
|
||
/** | ||
* Initialization method. | ||
*/ | ||
protected function init() { | ||
add_filter( 'get_block_templates', array( $this, 'add_block_templates' ), 10, 3 ); | ||
} | ||
|
||
/** | ||
* Add the block template objects to be used. | ||
* | ||
* @param array $query_result Array of template objects. | ||
* @return array | ||
*/ | ||
public function add_block_templates( $query_result ) { | ||
if ( ! gutenberg_supports_block_templates() ) { | ||
return $query_result; | ||
} | ||
|
||
$template_files = $this->get_block_templates(); | ||
|
||
foreach ( $template_files as $template_file ) { | ||
$query_result[] = BlockTemplateUtils::gutenberg_build_template_result_from_file( $template_file, 'wp_template' ); | ||
} | ||
|
||
return $query_result; | ||
} | ||
|
||
/** | ||
* Get and build the block template objects from the block template files. | ||
* | ||
* @return array | ||
*/ | ||
public function get_block_templates() { | ||
$template_files = BlockTemplateUtils::gutenberg_get_template_paths( $this->templates_directory ); | ||
$templates = array(); | ||
|
||
foreach ( $template_files as $template_file ) { | ||
$template_slug = substr( | ||
$template_file, | ||
strpos( $template_file, self::TEMPLATES_DIR_NAME . DIRECTORY_SEPARATOR ) + 1 + strlen( self::TEMPLATES_DIR_NAME ), | ||
-5 | ||
); | ||
|
||
// If the theme already has a template then there is no need to load ours in. | ||
if ( $this->theme_has_template( $template_slug ) ) { | ||
continue; | ||
} | ||
|
||
$new_template_item = array( | ||
'title' => ucwords( str_replace( '-', ' ', $template_slug ) ), | ||
'slug' => $template_slug, | ||
'path' => $template_file, | ||
'theme' => get_template_directory(), | ||
'type' => 'wp_template', | ||
); | ||
$templates[] = $new_template_item; | ||
} | ||
|
||
return $templates; | ||
} | ||
|
||
/** | ||
* Check if the theme has a template. So we know if to load our own in or not. | ||
* | ||
* @param string $template_name name of the template file without .html extension e.g. 'single-product'. | ||
* @return boolean | ||
*/ | ||
public function theme_has_template( $template_name ) { | ||
return is_readable( get_template_directory() . '/block-templates/' . $template_name . '.html' ) || | ||
is_readable( get_stylesheet_directory() . '/block-templates/' . $template_name . '.html' ); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
<?php | ||
namespace Automattic\WooCommerce\Blocks\Utils; | ||
|
||
/** | ||
* BlockTemplateUtils class used for serving block templates from Woo Blocks. | ||
* IMPORTANT: These methods have been duplicated from Gutenberg/lib/full-site-editing/block-templates.php as those functions are not for public usage. | ||
*/ | ||
class BlockTemplateUtils { | ||
/** | ||
* Returns an array containing the references of | ||
* the passed blocks and their inner blocks. | ||
* | ||
* @param array $blocks array of blocks. | ||
* | ||
* @return array block references to the passed blocks and their inner blocks. | ||
*/ | ||
public static function gutenberg_flatten_blocks( &$blocks ) { | ||
$all_blocks = array(); | ||
$queue = array(); | ||
foreach ( $blocks as &$block ) { | ||
$queue[] = &$block; | ||
} | ||
$queue_count = count( $queue ); | ||
|
||
while ( $queue_count > 0 ) { | ||
$block = &$queue[0]; | ||
array_shift( $queue ); | ||
$all_blocks[] = &$block; | ||
|
||
if ( ! empty( $block['innerBlocks'] ) ) { | ||
foreach ( $block['innerBlocks'] as &$inner_block ) { | ||
$queue[] = &$inner_block; | ||
} | ||
} | ||
|
||
$queue_count = count( $queue ); | ||
} | ||
|
||
return $all_blocks; | ||
} | ||
|
||
/** | ||
* Parses wp_template content and injects the current theme's | ||
* stylesheet as a theme attribute into each wp_template_part | ||
* | ||
* @param string $template_content serialized wp_template content. | ||
* | ||
* @return string Updated wp_template content. | ||
*/ | ||
public static function gutenberg_inject_theme_attribute_in_content( $template_content ) { | ||
$has_updated_content = false; | ||
$new_content = ''; | ||
$template_blocks = parse_blocks( $template_content ); | ||
|
||
$blocks = self::gutenberg_flatten_blocks( $template_blocks ); | ||
foreach ( $blocks as &$block ) { | ||
if ( | ||
'core/template-part' === $block['blockName'] && | ||
! isset( $block['attrs']['theme'] ) | ||
) { | ||
$block['attrs']['theme'] = wp_get_theme()->get_stylesheet(); | ||
$has_updated_content = true; | ||
} | ||
} | ||
|
||
if ( $has_updated_content ) { | ||
foreach ( $template_blocks as &$block ) { | ||
$new_content .= serialize_block( $block ); | ||
} | ||
|
||
return $new_content; | ||
} | ||
|
||
return $template_content; | ||
} | ||
|
||
/** | ||
* Build a unified template object based on a theme file. | ||
* | ||
* @param array $template_file Theme file. | ||
* @param array $template_type wp_template or wp_template_part. | ||
* | ||
* @return WP_Block_Template Template. | ||
*/ | ||
public static function gutenberg_build_template_result_from_file( $template_file, $template_type ) { | ||
$default_template_types = gutenberg_get_default_template_types(); | ||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents | ||
$template_content = file_get_contents( $template_file['path'] ); | ||
$theme = wp_get_theme()->get_stylesheet(); | ||
|
||
$template = new \WP_Block_Template(); | ||
$template->id = $theme . '//' . $template_file['slug']; | ||
$template->theme = $theme; | ||
$template->content = self::gutenberg_inject_theme_attribute_in_content( $template_content ); | ||
$template->slug = $template_file['slug']; | ||
$template->source = 'theme'; | ||
$template->type = $template_type; | ||
$template->title = ! empty( $template_file['title'] ) ? $template_file['title'] : $template_file['slug']; | ||
$template->status = 'publish'; | ||
$template->has_theme_file = true; | ||
|
||
if ( 'wp_template' === $template_type && isset( $default_template_types[ $template_file['slug'] ] ) ) { | ||
$template->description = $default_template_types[ $template_file['slug'] ]['description']; | ||
$template->title = $default_template_types[ $template_file['slug'] ]['title']; | ||
} | ||
|
||
if ( 'wp_template_part' === $template_type && isset( $template_file['area'] ) ) { | ||
$template->area = $template_file['area']; | ||
} | ||
|
||
return $template; | ||
} | ||
|
||
/** | ||
* Finds all nested template part file paths in a theme's directory. | ||
* | ||
* @param string $base_directory The theme's file path. | ||
* @return array $path_list A list of paths to all template part files. | ||
*/ | ||
public static function gutenberg_get_template_paths( $base_directory ) { | ||
$path_list = array(); | ||
if ( file_exists( $base_directory ) ) { | ||
$nested_files = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( $base_directory ) ); | ||
$nested_html_files = new \RegexIterator( $nested_files, '/^.+\.html$/i', \RecursiveRegexIterator::GET_MATCH ); | ||
foreach ( $nested_html_files as $path => $file ) { | ||
$path_list[] = $path; | ||
} | ||
} | ||
return $path_list; | ||
} | ||
} |