diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index bf7bb1bab92..a631eb4b918 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -163,10 +163,7 @@ public function get_single_block_template( $template, $id, $template_type ) { * @return array */ public function add_block_templates( $query_result, $query, $template_type ) { - if ( - ( ! function_exists( 'wp_is_block_theme' ) || ! wp_is_block_theme() ) && - ( ! function_exists( 'gutenberg_supports_block_templates' ) || ! gutenberg_supports_block_templates() ) - ) { + if ( ! BlockTemplateUtils::supports_block_templates() ) { return $query_result; } @@ -349,21 +346,25 @@ function ( $template ) use ( $template_slug ) { continue; } + // 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' ) ) { + $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; + } + // At this point the template only exists in the Blocks filesystem and has not been saved in the DB, // or superseded by the theme. - $new_template_item = array( - 'slug' => $template_slug, - 'id' => 'woocommerce//' . $template_slug, - 'path' => $template_file, - 'type' => $template_type, - 'theme' => 'woocommerce', - 'source' => 'plugin', - 'title' => BlockTemplateUtils::convert_slug_to_title( $template_slug ), - 'description' => '', - 'post_types' => array(), // Don't appear in any Edit Post template selector dropdown. - ); - $templates[] = (object) $new_template_item; + $templates[] = BlockTemplateUtils::create_new_block_template_object( $template_file, $template_type, $template_slug ); } + return $templates; } @@ -381,7 +382,6 @@ public function get_block_templates( $slugs = array(), $template_type = 'wp_temp return array_merge( $templates_from_db, $templates_from_woo ); } - /** * Gets the directory where templates of a specific template type can be found. * @@ -419,11 +419,7 @@ public function block_template_is_available( $template_name, $template_type = 'w * Renders the default block template from Woo Blocks if no theme templates exist. */ public function render_block_template() { - if ( - is_embed() || - ( ! function_exists( 'wp_is_block_theme' ) || ! wp_is_block_theme() ) && - ( ! function_exists( 'gutenberg_supports_block_templates' ) || ! gutenberg_supports_block_templates() ) - ) { + if ( is_embed() || ! BlockTemplateUtils::supports_block_templates() ) { return; } diff --git a/src/Utils/BlockTemplateUtils.php b/src/Utils/BlockTemplateUtils.php index e4b24eddaac..8988fb665f6 100644 --- a/src/Utils/BlockTemplateUtils.php +++ b/src/Utils/BlockTemplateUtils.php @@ -133,24 +133,61 @@ public static function gutenberg_build_template_result_from_post( $post ) { */ public static function gutenberg_build_template_result_from_file( $template_file, $template_type ) { $template_file = (object) $template_file; + + // If the theme has an archive-products.html template but does not have product taxonomy templates + // then we will load in the archive-product.html template from the theme to use for product taxonomies on the frontend. + $template_is_from_theme = 'theme' === $template_file->source; + $theme_name = wp_get_theme()->get( 'TextDomain' ); + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents - $template_content = file_get_contents( $template_file->path ); - $template = new \WP_Block_Template(); - $template->id = 'woocommerce//' . $template_file->slug; - $template->theme = 'WooCommerce'; - $template->content = self::gutenberg_inject_theme_attribute_in_content( $template_content ); + $template_content = file_get_contents( $template_file->path ); + $template = new \WP_Block_Template(); + $template->id = $template_is_from_theme ? $theme_name . '//' . $template_file->slug : 'woocommerce//' . $template_file->slug; + $template->theme = $template_is_from_theme ? $theme_name : 'WooCommerce'; + $template->content = self::gutenberg_inject_theme_attribute_in_content( $template_content ); + // Plugin was agreed as a valid source value despite existing inline docs at the time of creating: https://github.com/WordPress/gutenberg/issues/36597#issuecomment-976232909. + $template->source = $template_file->source ? $template_file->source : 'plugin'; $template->slug = $template_file->slug; $template->type = $template_type; $template->title = ! empty( $template_file->title ) ? $template_file->title : self::convert_slug_to_title( $template_file->slug ); $template->status = 'publish'; $template->has_theme_file = true; - $template->origin = 'plugin'; - $template->is_custom = false; + $template->origin = $template_file->source; + $template->is_custom = false; // Templates loaded from the filesystem aren't custom, ones that have been edited and loaded from the DB are. $template->post_types = array(); // Don't appear in any Edit Post template selector dropdown. $template->area = 'uncategorized'; return $template; } + /** + * Build a new template object so that we can make Woo Blocks default templates available in the current theme should they not have any. + * + * @param string $template_file Block template file path. + * @param string $template_type wp_template or wp_template_part. + * @param string $template_slug Block template slug e.g. single-product. + * @param bool $template_is_from_theme If the block template file is being loaded from the current theme instead of Woo Blocks. + * + * @return object Block template object. + */ + public static function create_new_block_template_object( $template_file, $template_type, $template_slug, $template_is_from_theme = false ) { + $theme_name = wp_get_theme()->get( 'TextDomain' ); + + $new_template_item = array( + 'slug' => $template_slug, + 'id' => $template_is_from_theme ? $theme_name . '//' . $template_slug : 'woocommerce//' . $template_slug, + 'path' => $template_file, + 'type' => $template_type, + 'theme' => $template_is_from_theme ? $theme_name : 'woocommerce', + // Plugin was agreed as a valid source value despite existing inline docs at the time of creating: https://github.com/WordPress/gutenberg/issues/36597#issuecomment-976232909. + 'source' => $template_is_from_theme ? 'theme' : 'plugin', + 'title' => self::convert_slug_to_title( $template_slug ), + 'description' => '', + 'post_types' => array(), // Don't appear in any Edit Post template selector dropdown. + ); + + return (object) $new_template_item; + } + /** * Finds all nested template part file paths in a theme's directory. * @@ -227,4 +264,20 @@ 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' ); } + + /** + * Checks to see if they are using a compatible version of WP, or if not they have a compatible version of the Gutenberg plugin installed. + * + * @return boolean + */ + public static function supports_block_templates() { + if ( + ( ! function_exists( 'wp_is_block_theme' ) || ! wp_is_block_theme() ) && + ( ! function_exists( 'gutenberg_supports_block_templates' ) || ! gutenberg_supports_block_templates() ) + ) { + return false; + } + + return true; + } }