From 0367117d15d305c3edb4462f53b3dbef29e278c3 Mon Sep 17 00:00:00 2001 From: Lucio Giannotta Date: Tue, 28 Dec 2021 23:32:15 +0100 Subject: [PATCH] Move block templates and parts directories to the Gutenberg 12.1.0 convention (https://github.com/woocommerce/woocommerce-blocks/pull/5455) Gutenberg 12.1.0 has changed the convention for the directory paths from `block-templates` and `block-template-parts` to `templates` and `parts` respectively. Allow compatibility with themes which follow both conventions and also make sure that we remain backwards-compatible. Fixes woocommerce/woocommerce-blocks#5450 Some of this fix has a dependency on WooCore See: WooCommerce/woocommercewoocommerce/woocommerce-blocks#31522 --- .../src/BlockTemplatesController.php | 2 +- .../src/Utils/BlockTemplateUtils.php | 82 +++++++++++++++++-- 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/plugins/woocommerce-blocks/src/BlockTemplatesController.php b/plugins/woocommerce-blocks/src/BlockTemplatesController.php index c8abf43ce5c..be1fa2ea7da 100644 --- a/plugins/woocommerce-blocks/src/BlockTemplatesController.php +++ b/plugins/woocommerce-blocks/src/BlockTemplatesController.php @@ -343,7 +343,7 @@ class BlockTemplatesController { // If the theme has an archive-product.html template, but not a taxonomy-product_cat.html template let's use the themes archive-product.html template. if ( BlockTemplateUtils::template_is_eligible_for_product_archive_fallback( $template_slug ) ) { - $template_file = get_stylesheet_directory() . '/' . self::TEMPLATES_DIR_NAME . '/archive-product.html'; + $template_file = BlockTemplateUtils::get_theme_template_path( 'archive-product' ); $templates[] = BlockTemplateUtils::create_new_block_template_object( $template_file, $template_type, $template_slug, true ); continue; } diff --git a/plugins/woocommerce-blocks/src/Utils/BlockTemplateUtils.php b/plugins/woocommerce-blocks/src/Utils/BlockTemplateUtils.php index cbc61f39e77..8b6d793a63b 100644 --- a/plugins/woocommerce-blocks/src/Utils/BlockTemplateUtils.php +++ b/plugins/woocommerce-blocks/src/Utils/BlockTemplateUtils.php @@ -6,6 +6,27 @@ namespace Automattic\WooCommerce\Blocks\Utils; * 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 { + /** + * Directory names for block templates + * + * Directory names conventions for block templates have changed with Gutenberg 12.1.0, + * however, for backwards-compatibility, we also keep the older conventions, prefixed + * with `DEPRECATED_`. + * + * @var array { + * @var string DEPRECATED_TEMPLATES Old directory name of the block templates directory. + * @var string DEPRECATED_TEMPLATE_PARTS Old directory name of the block template parts directory. + * @var string TEMPLATES_DIR_NAME Directory name of the block templates directory. + * @var string TEMPLATE_PARTS_DIR_NAME Directory name of the block template parts directory. + * } + */ + const DIRECTORY_NAMES = array( + 'DEPRECATED_TEMPLATES' => 'block-templates', + 'DEPRECATED_TEMPLATE_PARTS' => 'block-template-parts', + 'TEMPLATES' => 'templates', + 'TEMPLATE_PARTS' => 'parts', + ); + /** * Returns an array containing the references of * the passed blocks and their inner blocks. @@ -244,6 +265,57 @@ class BlockTemplateUtils { ); } + /** + * Gets the first matching template part within themes directories + * + * Since [Gutenberg 12.1.0](https://github.com/WordPress/gutenberg/releases/tag/v12.1.0), the conventions for + * block templates and parts directory has changed from `block-templates` and `block-templates-parts` + * to `templates` and `parts` respectively. + * + * This function traverses all possible combinations of directory paths where a template or part + * could be located and returns the first one which is readable, prioritizing the new convention + * over the deprecated one, but maintaining that one for backwards compatibility. + * + * @param string $template_slug The slug of the template (i.e. without the file extension). + * @param string $template_type Either `wp_template` or `wp_template_part`. + * + * @return string|null The matched path or `null` if no match was found. + */ + public static function get_theme_template_path( $template_slug, $template_type = 'wp_template' ) { + $template_filename = $template_slug . '.html'; + $possible_templates_dir = 'wp_template' === $template_type ? array( + self::DIRECTORY_NAMES['TEMPLATES'], + self::DIRECTORY_NAMES['DEPRECATED_TEMPLATES'], + ) : array( + self::DIRECTORY_NAMES['TEMPLATE_PARTS'], + self::DIRECTORY_NAMES['DEPRECATED_TEMPLATE_PARTS'], + ); + + // Combine the possible root directory names with either the template directory + // or the stylesheet directory for child themes. + $possible_paths = array_reduce( + $possible_templates_dir, + function( $carry, $item ) use ( $template_filename ) { + $filepath = DIRECTORY_SEPARATOR . $item . DIRECTORY_SEPARATOR . $template_filename; + + $carry[] = get_template_directory() . $filepath; + $carry[] = get_stylesheet_directory() . $filepath; + + return $carry; + }, + array() + ); + + // Return the first matching. + foreach ( $possible_paths as $path ) { + if ( is_readable( $path ) ) { + return $path; + } + } + + return null; + } + /** * Check if the theme has a template. So we know if to load our own in or not. * @@ -251,8 +323,7 @@ class BlockTemplateUtils { * @return boolean */ public static 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' ); + return ! ! self::get_theme_template_path( $template_name, 'wp_template' ); } /** @@ -262,8 +333,7 @@ class BlockTemplateUtils { * @return boolean */ public static function theme_has_template_part( $template_name ) { - return is_readable( get_template_directory() . '/block-template-parts/' . $template_name . '.html' ) || - is_readable( get_stylesheet_directory() . '/block-template-parts/' . $template_name . '.html' ); + return ! ! self::get_theme_template_path( $template_name, 'wp_template_part' ); } /** @@ -311,8 +381,8 @@ class BlockTemplateUtils { * * It returns `true` if anything was changed, `false` otherwise. * - * @param array $query_result Array of template objects. - * @param array $template A specific template object which could have a fallback. + * @param array $query_result Array of template objects. + * @param object $template A specific template object which could have a fallback. * * @return boolean */