diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index 48fae793464..c8abf43ce5c 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -175,16 +175,10 @@ public function add_block_templates( $query_result, $query, $template_type ) { // @todo: Add apply_filters to _gutenberg_get_template_files() in Gutenberg to prevent duplication of logic. foreach ( $template_files as $template_file ) { - // Avoid adding the same template if it's already in the array of $query_result. - if ( - array_filter( - $query_result, - function( $query_result_template ) use ( $template_file ) { - return $query_result_template->slug === $template_file->slug && - $query_result_template->theme === $template_file->theme; - } - ) - ) { + // If we have a template which is eligible for a fallback, we need to explicitly tell Gutenberg that + // it has a theme file (because it is using the fallback template file). And then `continue` to avoid + // adding duplicates. + if ( BlockTemplateUtils::set_has_theme_file_if_fallback_is_available( $query_result, $template_file ) ) { continue; } @@ -348,14 +342,7 @@ function ( $template ) use ( $template_slug ) { } // 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 ( 'taxonomy-product_cat' === $template_slug && ! BlockTemplateUtils::theme_has_template( 'taxonomy-product_cat' ) && BlockTemplateUtils::theme_has_template( 'archive-product' ) ) { - $template_file = get_stylesheet_directory() . '/' . self::TEMPLATES_DIR_NAME . '/archive-product.html'; - $templates[] = BlockTemplateUtils::create_new_block_template_object( $template_file, $template_type, $template_slug, true ); - continue; - } - - // If the theme has an archive-product.html template, but not a taxonomy-product_tag.html template let's use the themes archive-product.html template. - if ( 'taxonomy-product_tag' === $template_slug && ! BlockTemplateUtils::theme_has_template( 'taxonomy-product_tag' ) && BlockTemplateUtils::theme_has_template( 'archive-product' ) ) { + if ( BlockTemplateUtils::template_is_eligible_for_product_archive_fallback( $template_slug ) ) { $template_file = get_stylesheet_directory() . '/' . self::TEMPLATES_DIR_NAME . '/archive-product.html'; $templates[] = BlockTemplateUtils::create_new_block_template_object( $template_file, $template_type, $template_slug, true ); continue; diff --git a/src/Utils/BlockTemplateUtils.php b/src/Utils/BlockTemplateUtils.php index 3ef2e3aa318..52ca21ffa48 100644 --- a/src/Utils/BlockTemplateUtils.php +++ b/src/Utils/BlockTemplateUtils.php @@ -281,4 +281,55 @@ public static function supports_block_templates() { return true; } + + /** + * Checks if we can fallback to the `archive-product` template for a given slug + * + * `taxonomy-product_cat` and `taxonomy-product_tag` templates can generally use the + * `archive-product` as a fallback if there are no specific overrides. + * + * @param string $template_slug Slug to check for fallbacks. + * @return boolean + */ + public static function template_is_eligible_for_product_archive_fallback( $template_slug ) { + $eligible_for_fallbacks = array( 'taxonomy-product_cat', 'taxonomy-product_tag' ); + + return in_array( $template_slug, $eligible_for_fallbacks, true ) + && ! self::theme_has_template( $template_slug ) + && self::theme_has_template( 'archive-product' ); + } + + /** + * Sets the `has_theme_file` to `true` for templates with fallbacks + * + * There are cases (such as tags and categories) in which fallback templates + * can be used; so, while *technically* the theme doesn't have a specific file + * for them, it is important that we tell Gutenberg that we do, in fact, + * have a theme file (i.e. the fallback one). + * + * **Note:** this function changes the array that has been passed. + * + * 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. + * + * @return boolean + */ + public static function set_has_theme_file_if_fallback_is_available( $query_result, $template ) { + foreach ( $query_result as &$query_result_template ) { + if ( + $query_result_template->slug === $template->slug + && $query_result_template->theme === $template->theme + ) { + if ( self::template_is_eligible_for_product_archive_fallback( $template->slug ) ) { + $query_result_template->has_theme_file = true; + } + + return true; + } + } + + return false; + } }