From 848303b15144b34f34e31cc45439b6aecf805c92 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Wed, 3 Nov 2021 08:06:10 +0000 Subject: [PATCH 01/25] Ensure $template is object before accessing properties This is necessary because the gutenberg helper functions sometimes turn it into a WP_Block_Template object, and other times it's an array. Because of this it's safer to normalise them both as objects. --- src/Utils/BlockTemplateUtils.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Utils/BlockTemplateUtils.php b/src/Utils/BlockTemplateUtils.php index d248ddeb1a6..6ae47efdfcb 100644 --- a/src/Utils/BlockTemplateUtils.php +++ b/src/Utils/BlockTemplateUtils.php @@ -83,23 +83,24 @@ public static function gutenberg_inject_theme_attribute_in_content( $template_co * @return \WP_Block_Template Template. */ public static function gutenberg_build_template_result_from_file( $template_file, $template_type ) { + $template_file = (object) $template_file; + $default_template_types = function_exists( 'gutenberg_get_default_template_types' ) ? gutenberg_get_default_template_types() : array(); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents - $template_content = file_get_contents( $template_file['path'] ); + $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->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 = 'woocommerce'; + $template->slug = $template_file->slug; $template->type = $template_type; - $template->title = ! empty( $template_file['title'] ) ? $template_file['title'] : $template_file['slug']; + $template->title = ! empty( $template_file->title ) ? $template_file->title : $template_file->slug; $template->status = 'publish'; $template->has_theme_file = true; $template->is_custom = false; // Templates loaded from the filesystem aren't custom, ones that have been edited and loaded from the DB are. $template->title = self::convert_slug_to_title( $template_file['slug'] ); - return $template; } From 5acf2b65382b81d63946a2af4db223661e4ab06b Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Wed, 3 Nov 2021 08:08:57 +0000 Subject: [PATCH 02/25] Add Gutenberg utils for processing templates based on a post from the db When a template is saved it gets saved to the database, we need to handle processing these WooCommerce templates that have been saved in the db and we need to use the gutenberg utils that are private, this is why they've been copied over. --- src/Utils/BlockTemplateUtils.php | 139 ++++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 1 deletion(-) diff --git a/src/Utils/BlockTemplateUtils.php b/src/Utils/BlockTemplateUtils.php index 6ae47efdfcb..c6a64581f18 100644 --- a/src/Utils/BlockTemplateUtils.php +++ b/src/Utils/BlockTemplateUtils.php @@ -74,6 +74,143 @@ public static function gutenberg_inject_theme_attribute_in_content( $template_co return $template_content; } + + /** + * Attempts to add custom template information to the template item. + * + * @param array $template_item Template to add information to (requires 'slug' field). + * @return array Template + */ + public static function gutenberg_add_template_info( $template_item ) { + if ( ! \WP_Theme_JSON_Resolver_Gutenberg::theme_has_support() ) { + return $template_item; + } + + $theme_data = \WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_custom_templates(); + if ( isset( $theme_data[ $template_item['slug'] ] ) ) { + $template_item['title'] = $theme_data[ $template_item['slug'] ]['title']; + $template_item['postTypes'] = $theme_data[ $template_item['slug'] ]['postTypes']; + } + + return $template_item; + } + + /** + * Retrieves the template file from the theme for a given slug. + * + * @internal + * + * @param string $template_type wp_template or wp_template_part. + * @param string $slug template slug. + * + * @return array|null Template. + */ + public static function gutenberg_get_template_file( $template_type, $slug ) { + $template_base_paths = array( + 'wp_template' => 'block-templates', + 'wp_template_part' => 'block-template-parts', + ); + $themes = array( + get_stylesheet() => get_stylesheet_directory(), + get_template() => get_template_directory(), + ); + foreach ( $themes as $theme_slug => $theme_dir ) { + $file_path = $theme_dir . '/' . $template_base_paths[ $template_type ] . '/' . $slug . '.html'; + if ( file_exists( $file_path ) ) { + $new_template_item = array( + 'slug' => $slug, + 'path' => $file_path, + 'theme' => $theme_slug, + 'type' => $template_type, + ); + + if ( 'wp_template_part' === $template_type ) { + return self::gutenberg_add_template_part_area_info( $new_template_item ); + } + + if ( 'wp_template' === $template_type ) { + return self::gutenberg_add_template_info( $new_template_item ); + } + + return $new_template_item; + } + } + + return null; + } + + /** + * Attempts to add the template part's area information to the input template. + * + * @param array $template_info Template to add information to (requires 'type' and 'slug' fields). + * + * @return array Template. + */ + public static function gutenberg_add_template_part_area_info( $template_info ) { + if ( \WP_Theme_JSON_Resolver_Gutenberg::theme_has_support() ) { + $theme_data = \WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_template_parts(); + } + + if ( isset( $theme_data[ $template_info['slug'] ]['area'] ) ) { + $template_info['title'] = $theme_data[ $template_info['slug'] ]['title']; + $template_info['area'] = gutenberg_filter_template_part_area( $theme_data[ $template_info['slug'] ]['area'] ); + } else { + $template_info['area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED; + } + + return $template_info; + } + + /** + * Build a unified template object based a post Object. + * + * @param \WP_Post $post Template post. + * + * @return \WP_Block_Template|\WP_Error Template. + */ + public static function gutenberg_build_template_result_from_post( $post ) { + $default_template_types = gutenberg_get_default_template_types(); + $terms = get_the_terms( $post, 'wp_theme' ); + + if ( is_wp_error( $terms ) ) { + return $terms; + } + + if ( ! $terms ) { + return new \WP_Error( 'template_missing_theme', __( 'No theme is defined for this template.', 'woo-gutenberg-products-block' ) ); + } + + $theme = $terms[0]->name; + $has_theme_file = true; + + $template = new \WP_Block_Template(); + $template->wp_id = $post->ID; + $template->id = $theme . '//' . $post->post_name; + $template->theme = $theme; + $template->content = $post->post_content; + $template->slug = $post->post_name; + $template->source = 'custom'; + $template->type = $post->post_type; + $template->description = $post->post_excerpt; + $template->title = $post->post_title; + $template->status = $post->post_status; + $template->has_theme_file = $has_theme_file; + $template->is_custom = true; + + if ( 'wp_template' === $post->post_type && isset( $default_template_types[ $template->slug ] ) ) { + $template->is_custom = false; + } + + if ( 'wp_template_part' === $post->post_type ) { + $type_terms = get_the_terms( $post, 'wp_template_part_area' ); + if ( ! is_wp_error( $type_terms ) && false !== $type_terms ) { + $template->area = $type_terms[0]->name; + } + } + + return $template; + } + /** * Build a unified template object based on a theme file. * @@ -83,7 +220,7 @@ public static function gutenberg_inject_theme_attribute_in_content( $template_co * @return \WP_Block_Template Template. */ public static function gutenberg_build_template_result_from_file( $template_file, $template_type ) { - $template_file = (object) $template_file; + $template_file = (object) $template_file; $default_template_types = function_exists( 'gutenberg_get_default_template_types' ) ? gutenberg_get_default_template_types() : array(); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents $template_content = file_get_contents( $template_file->path ); From 4bfbc4a487b1d61c84cc753c49a931709a26e759 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Wed, 3 Nov 2021 10:00:43 +0000 Subject: [PATCH 03/25] Force theme to always be WooCommerce This is because the templates we're dealing with here should always belong to WooCommerce, not the currently selected theme --- src/Utils/BlockTemplateUtils.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Utils/BlockTemplateUtils.php b/src/Utils/BlockTemplateUtils.php index c6a64581f18..18b513b0904 100644 --- a/src/Utils/BlockTemplateUtils.php +++ b/src/Utils/BlockTemplateUtils.php @@ -227,8 +227,8 @@ public static function gutenberg_build_template_result_from_file( $template_file $theme = wp_get_theme()->get_stylesheet(); $template = new \WP_Block_Template(); - $template->id = $theme . '//' . $template_file->slug; - $template->theme = $theme; + $template->id = 'woocommerce//' . $template_file->slug; + $template->theme = 'woocommerce'; $template->content = self::gutenberg_inject_theme_attribute_in_content( $template_content ); $template->source = 'woocommerce'; $template->slug = $template_file->slug; From 5a5e6fb9c3fd1eafa326a0e9bb503eeb5542b2b4 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Wed, 3 Nov 2021 10:25:14 +0000 Subject: [PATCH 04/25] Add maybe_return_blocks_template and get_single_block_template funcs These are needed to get the template from either the DB or the filesystem when saving/retrieving the template. --- src/BlockTemplatesController.php | 91 ++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index db0738b40fb..7f8e88eec7b 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -38,6 +38,97 @@ public function __construct() { protected function init() { add_filter( 'get_block_templates', array( $this, 'add_block_templates' ), 10, 3 ); add_action( 'template_redirect', array( $this, 'render_block_template' ) ); + add_filter( 'pre_get_block_template', array( $this, 'maybe_return_blocks_template' ), 10, 3 ); + } + + /** + * This function checks if there's a blocks template (ultimately it resolves either a saved blocks template from the + * database or a template file in `woo-gutenberg-products/block/templates/block-templates/`) + * to return to pre_get_posts short-circuiting the query in Gutenberg. + * + * @param \WP_Block_Template|null $template Return a block template object to short-circuit the default query, + * or null to allow WP to run its normal queries. + * @param string $id Template unique identifier (example: theme_slug//template_slug). + * @param array $template_type wp_template or wp_template_part. + * + * @return mixed|\WP_Block_Template|\WP_Error + */ + public function maybe_return_blocks_template( $template, $id, $template_type ) { + $template_name_parts = explode( '//', $id ); + if ( count( $template_name_parts ) < 2 ) { + return $template; + } + list( , $slug ) = $template_name_parts; + + // Remove the filter at this point because if we don't then this function will infinite loop. + remove_filter( 'pre_get_block_template', array( $this, 'maybe_return_blocks_template' ), 10, 3 ); + + // Check if the theme has a saved version of this template before falling back to the woo one. Please note how + // the slug has not been modified at this point, we're still using the default one passed to this hook. + $maybe_template = gutenberg_get_block_template( $id, $template_type ); + if ( null !== $maybe_template ) { + return $maybe_template; + } + + // Theme-based template didn't exist, try switching the theme to woocommerce and try again. This function has + // been unhooked so won't run again. + add_filter( 'get_block_template', array( $this, 'get_single_block_template' ), 10, 3 ); + $maybe_template = gutenberg_get_block_template( 'woocommerce//' . $slug, $template_type ); + + // Re-hook this function, it was only unhooked to stop recursion. + add_filter( 'pre_get_block_template', array( $this, 'maybe_return_blocks_template' ), 10, 3 ); + remove_filter( 'get_block_template', array( $this, 'get_single_block_template' ), 10, 3 ); + if ( null !== $maybe_template ) { + return $maybe_template; + } + + // At this point we haven't had any luck finding a template. Give up and let Gutenberg take control again. + return $template; + } + + /** + * Runs on the get_block_template hook. If a template is already found and passed to this function, then return it + * and don't run. + * If a template is *not* passed, try to look for one that matches the ID in the database, if that's not found defer + * to Blocks templates files. Priority goes: DB-Theme, DB-Blocks, Filesystem-Theme, Filesystem-Blocks. + * + * @param \WP_Block_Template $template The found block template. + * @param string $id Template unique identifier (example: theme_slug//template_slug). + * @param array $template_type wp_template or wp_template_part. + * + * @return mixed|null + */ + public function get_single_block_template( $template, $id, $template_type ) { + + // The template was already found before the filter runs, just return it immediately. + if ( null !== $template ) { + return $template; + } + + $template_name_parts = explode( '//', $id ); + if ( count( $template_name_parts ) < 2 ) { + return $template; + } + list( , $slug ) = $template_name_parts; + + // If this blocks template doesn't exist then we should just skip the function and let Gutenberg handle it. + if ( ! $this->default_block_template_is_available( $slug ) ) { + return $template; + } + + $available_templates = $this->get_block_templates(); + + // array_values is used to rebase the array back to being 0-indexed. + $matched_templates = array_values( + array_filter( + $available_templates, + function( $available_template ) use ( $slug ) { + $available_template = (object) $available_template; + return $available_template->slug === $slug; + } + ) + ); + return count( $matched_templates > 0 ) ? (object) $matched_templates[0] : $template; } /** From 4819f6340500a5cae3f078530581460548cf7330 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Wed, 3 Nov 2021 10:37:57 +0000 Subject: [PATCH 05/25] Set theme to always be woocommerce when making templates from files This will ensure the correct slug is used in the gutenberg editor. --- src/BlockTemplatesController.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index 7f8e88eec7b..b9c641d7ab7 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -201,11 +201,14 @@ public function get_block_templates() { 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, - 'path' => $template_file, - 'theme' => get_template_directory(), - 'type' => 'wp_template', + 'slug'. => $template_slug, + 'path'. => $template_file, + 'type' => 'wp_template', + 'theme' => 'woocommerce', + 'description' => '', ); $templates[] = $new_template_item; } From 5c4b0ed790b81334e1a67b5f1bc324056acb69bb Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Wed, 3 Nov 2021 10:46:28 +0000 Subject: [PATCH 06/25] Check if template has been customised and saved in the database first --- src/BlockTemplatesController.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index b9c641d7ab7..07e41008a87 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -189,6 +189,27 @@ public function get_block_templates() { $template_files = BlockTemplateUtils::gutenberg_get_template_paths( $this->templates_directory ); $templates = array(); + // Check if the template has been saved in the database first. + $check_query_args = array( + 'post_type' => 'wp_template', + 'posts_per_page' => -1, + 'no_found_rows' => true, + 'tax_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query + array( + 'taxonomy' => 'wp_theme', + 'field' => 'name', + 'terms' => 'woocommerce', + ), + ), + ); + $check_query = new \WP_Query( $check_query_args ); + $saved_woo_templates = $check_query->posts; + + // From a WordPress post, build the template object and add it to our list. + foreach ( $saved_woo_templates as $saved_woo_template ) { + $templates[] = BlockTemplateUtils::gutenberg_build_template_result_from_post( $saved_woo_template ); + } + foreach ( $template_files as $template_file ) { $template_slug = substr( $template_file, From 495f4d25a8f4c09d54081e60a5054bca9787f83a Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Wed, 3 Nov 2021 10:49:23 +0000 Subject: [PATCH 07/25] Prevent filesystem templates being used if a custom database one exists --- src/BlockTemplatesController.php | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index 07e41008a87..f4bde9a0b72 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -149,11 +149,15 @@ 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 ) { - $template = BlockTemplateUtils::gutenberg_build_template_result_from_file( $template_file, 'wp_template' ); - - if ( $post_type && ! $template->is_custom ) { + + // It would be custom if the template was modified in the editor, so if it's not custom we can load it from + // the filesystem. + if ( $post_type && 'custom' !== $template_file->source ) { + $query_result[] = BlockTemplateUtils::gutenberg_build_template_result_from_file( $template_file, 'wp_template' ); continue; } + + $template = BlockTemplateUtils::gutenberg_build_template_result_from_file( $template_file, 'wp_template' ); if ( $post_type && isset( $template->post_types ) && @@ -175,6 +179,7 @@ public function add_block_templates( $query_result, $query, $template_type ) { if ( $should_include ) { $query_result[] = $template; } + } return $query_result; @@ -217,8 +222,19 @@ public function get_block_templates() { -5 ); - // If the theme already has a template then there is no need to load ours in. - if ( $this->theme_has_template( $template_slug ) ) { + // If the theme already has a template, or the template is already in the list (i.e. it came from the + // database) then we should not overwrite it with the one from the filesystem. + if ( + $this->theme_has_template( $template_slug ) || + count( + array_filter( + $templates, + function ( $template ) use ( $template_slug ) { + $template_obj = (object) $template; //phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.Found + return $template_obj->slug === $template_slug; + } + ) + ) > 0 ) { continue; } From 3cc5e670039fa660bc0e1da8111a6afa009a86ab Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Wed, 3 Nov 2021 17:09:54 +0000 Subject: [PATCH 08/25] Fix syntax error from rebase --- src/BlockTemplatesController.php | 11 +++++------ src/Utils/BlockTemplateUtils.php | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index f4bde9a0b72..7ffcfc48ec0 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -149,14 +149,14 @@ 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 ) { - - // It would be custom if the template was modified in the editor, so if it's not custom we can load it from + + // It would be custom if the template was modified in the editor, so if it's not custom we can load it from // the filesystem. if ( $post_type && 'custom' !== $template_file->source ) { $query_result[] = BlockTemplateUtils::gutenberg_build_template_result_from_file( $template_file, 'wp_template' ); continue; } - + $template = BlockTemplateUtils::gutenberg_build_template_result_from_file( $template_file, 'wp_template' ); if ( $post_type && @@ -179,7 +179,6 @@ public function add_block_templates( $query_result, $query, $template_type ) { if ( $should_include ) { $query_result[] = $template; } - } return $query_result; @@ -241,8 +240,8 @@ function ( $template ) use ( $template_slug ) { // 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, - 'path'. => $template_file, + 'slug' => $template_slug, + 'path' => $template_file, 'type' => 'wp_template', 'theme' => 'woocommerce', 'description' => '', diff --git a/src/Utils/BlockTemplateUtils.php b/src/Utils/BlockTemplateUtils.php index 18b513b0904..57660ad98e9 100644 --- a/src/Utils/BlockTemplateUtils.php +++ b/src/Utils/BlockTemplateUtils.php @@ -237,7 +237,7 @@ public static function gutenberg_build_template_result_from_file( $template_file $template->status = 'publish'; $template->has_theme_file = true; $template->is_custom = false; // Templates loaded from the filesystem aren't custom, ones that have been edited and loaded from the DB are. - $template->title = self::convert_slug_to_title( $template_file['slug'] ); + $template->title = self::convert_slug_to_title( $template_file->slug ); return $template; } From 46d467851ec4205bf12b429037f6552ca8f8b9a7 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Thu, 4 Nov 2021 09:09:11 +0000 Subject: [PATCH 09/25] Remove unnecessary code from BlockTemplateUtils --- src/Utils/BlockTemplateUtils.php | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/src/Utils/BlockTemplateUtils.php b/src/Utils/BlockTemplateUtils.php index 57660ad98e9..abde33a5c86 100644 --- a/src/Utils/BlockTemplateUtils.php +++ b/src/Utils/BlockTemplateUtils.php @@ -123,16 +123,7 @@ public static function gutenberg_get_template_file( $template_type, $slug ) { 'theme' => $theme_slug, 'type' => $template_type, ); - - if ( 'wp_template_part' === $template_type ) { - return self::gutenberg_add_template_part_area_info( $new_template_item ); - } - - if ( 'wp_template' === $template_type ) { - return self::gutenberg_add_template_info( $new_template_item ); - } - - return $new_template_item; + return self::gutenberg_add_template_info( $new_template_item ); } } @@ -169,8 +160,7 @@ public static function gutenberg_add_template_part_area_info( $template_info ) { * @return \WP_Block_Template|\WP_Error Template. */ public static function gutenberg_build_template_result_from_post( $post ) { - $default_template_types = gutenberg_get_default_template_types(); - $terms = get_the_terms( $post, 'wp_theme' ); + $terms = get_the_terms( $post, 'wp_theme' ); if ( is_wp_error( $terms ) ) { return $terms; @@ -197,17 +187,6 @@ public static function gutenberg_build_template_result_from_post( $post ) { $template->has_theme_file = $has_theme_file; $template->is_custom = true; - if ( 'wp_template' === $post->post_type && isset( $default_template_types[ $template->slug ] ) ) { - $template->is_custom = false; - } - - if ( 'wp_template_part' === $post->post_type ) { - $type_terms = get_the_terms( $post, 'wp_template_part_area' ); - if ( ! is_wp_error( $type_terms ) && false !== $type_terms ) { - $template->area = $type_terms[0]->name; - } - } - return $template; } @@ -220,12 +199,9 @@ public static function gutenberg_build_template_result_from_post( $post ) { * @return \WP_Block_Template Template. */ public static function gutenberg_build_template_result_from_file( $template_file, $template_type ) { - $template_file = (object) $template_file; - $default_template_types = function_exists( 'gutenberg_get_default_template_types' ) ? gutenberg_get_default_template_types() : array(); + $template_file = (object) $template_file; // 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_content = file_get_contents( $template_file->path ); $template = new \WP_Block_Template(); $template->id = 'woocommerce//' . $template_file->slug; $template->theme = 'woocommerce'; From 2d53a52d2120dd75655fbb90917f9d44996d6971 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Thu, 4 Nov 2021 12:58:50 +0000 Subject: [PATCH 10/25] Ensure template item is an object containing correct properties --- src/BlockTemplatesController.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index 7ffcfc48ec0..1575a463882 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -241,12 +241,14 @@ function ( $template ) use ( $template_slug ) { // or superseded by the theme. $new_template_item = array( 'slug' => $template_slug, + 'id' => 'woocommerce//' . $template_slug, 'path' => $template_file, 'type' => 'wp_template', 'theme' => 'woocommerce', + 'source' => 'theme', 'description' => '', ); - $templates[] = $new_template_item; + $templates[] = (object) $new_template_item; } return $templates; } From 28285538fb9013f3c2c7936276d1ca13766189b8 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Thu, 4 Nov 2021 13:08:47 +0000 Subject: [PATCH 11/25] Prevent warnings from appearing --- src/BlockTemplatesController.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index 1575a463882..b8971a719c6 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -128,7 +128,7 @@ function( $available_template ) use ( $slug ) { } ) ); - return count( $matched_templates > 0 ) ? (object) $matched_templates[0] : $template; + return ( is_array( $matched_templates ) && count( $matched_templates ) > 0 ) ? (object) $matched_templates[0] : $template; } /** @@ -152,13 +152,14 @@ public function add_block_templates( $query_result, $query, $template_type ) { // It would be custom if the template was modified in the editor, so if it's not custom we can load it from // the filesystem. - if ( $post_type && 'custom' !== $template_file->source ) { - $query_result[] = BlockTemplateUtils::gutenberg_build_template_result_from_file( $template_file, 'wp_template' ); + if ( 'custom' !== $template_file->source ) { + $template = BlockTemplateUtils::gutenberg_build_template_result_from_file( $template_file, 'wp_template' ); + } else { + $template_file->title = BlockTemplateUtils::convert_slug_to_title( $template_file->slug ); + $query_result[] = $template_file; continue; } - $template = BlockTemplateUtils::gutenberg_build_template_result_from_file( $template_file, 'wp_template' ); - if ( $post_type && isset( $template->post_types ) && ! in_array( $post_type, $template->post_types, true ) @@ -167,14 +168,14 @@ public function add_block_templates( $query_result, $query, $template_type ) { } $is_not_custom = false === array_search( - wp_get_theme()->get_stylesheet() . '//' . $template_file['slug'], + wp_get_theme()->get_stylesheet() . '//' . $template_file->slug, array_column( $query_result, 'id' ), true ); $fits_slug_query = - ! isset( $query['slug__in'] ) || in_array( $template_file['slug'], $query['slug__in'], true ); + ! isset( $query['slug__in'] ) || in_array( $template_file->slug, $query['slug__in'], true ); $fits_area_query = - ! isset( $query['area'] ) || $template_file['area'] === $query['area']; + ! isset( $query['area'] ) || $template_file->area === $query['area']; $should_include = $is_not_custom && $fits_slug_query && $fits_area_query; if ( $should_include ) { $query_result[] = $template; @@ -245,7 +246,7 @@ function ( $template ) use ( $template_slug ) { 'path' => $template_file, 'type' => 'wp_template', 'theme' => 'woocommerce', - 'source' => 'theme', + 'source' => 'woocommerce', 'description' => '', ); $templates[] = (object) $new_template_item; From 00d2cdcc2fc426506b3bb92f28ededd7c6fd3076 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Thu, 4 Nov 2021 13:47:54 +0000 Subject: [PATCH 12/25] Ensure title is added to the template when saving --- src/BlockTemplatesController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index b8971a719c6..a00eb034132 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -247,6 +247,7 @@ function ( $template ) use ( $template_slug ) { 'type' => 'wp_template', 'theme' => 'woocommerce', 'source' => 'woocommerce', + 'title' => BlockTemplateUtils::convert_slug_to_title( $template_slug ), 'description' => '', ); $templates[] = (object) $new_template_item; From 12fddc92c84a407a637795dd312c2a4142b2e276 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Fri, 5 Nov 2021 08:57:02 +0000 Subject: [PATCH 13/25] Filter templates that don't match the queried slug. --- src/BlockTemplatesController.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index a00eb034132..8f443d48a45 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -147,6 +147,18 @@ public function add_block_templates( $query_result, $query, $template_type ) { $post_type = isset( $query['post_type'] ) ? $query['post_type'] : ''; $template_files = $this->get_block_templates(); + if ( isset( $query['slug__in'] ) ) { + // Get only the template files that match the slugs requested in the query. + $template_files = array_values( + array_filter( + $template_files, + function ( $template ) use ( $query ) { + return in_array( $template->slug, $query['slug__in'], true ); + } + ) + ); + } + // @todo: Add apply_filters to _gutenberg_get_template_files() in Gutenberg to prevent duplication of logic. foreach ( $template_files as $template_file ) { From ff8293b795777ddb26f287d05e496ea37f46875e Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Fri, 5 Nov 2021 08:57:34 +0000 Subject: [PATCH 14/25] Remove unused code --- src/Utils/BlockTemplateUtils.php | 78 -------------------------------- 1 file changed, 78 deletions(-) diff --git a/src/Utils/BlockTemplateUtils.php b/src/Utils/BlockTemplateUtils.php index abde33a5c86..abf1c721e60 100644 --- a/src/Utils/BlockTemplateUtils.php +++ b/src/Utils/BlockTemplateUtils.php @@ -74,84 +74,6 @@ public static function gutenberg_inject_theme_attribute_in_content( $template_co return $template_content; } - - /** - * Attempts to add custom template information to the template item. - * - * @param array $template_item Template to add information to (requires 'slug' field). - * @return array Template - */ - public static function gutenberg_add_template_info( $template_item ) { - if ( ! \WP_Theme_JSON_Resolver_Gutenberg::theme_has_support() ) { - return $template_item; - } - - $theme_data = \WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_custom_templates(); - if ( isset( $theme_data[ $template_item['slug'] ] ) ) { - $template_item['title'] = $theme_data[ $template_item['slug'] ]['title']; - $template_item['postTypes'] = $theme_data[ $template_item['slug'] ]['postTypes']; - } - - return $template_item; - } - - /** - * Retrieves the template file from the theme for a given slug. - * - * @internal - * - * @param string $template_type wp_template or wp_template_part. - * @param string $slug template slug. - * - * @return array|null Template. - */ - public static function gutenberg_get_template_file( $template_type, $slug ) { - $template_base_paths = array( - 'wp_template' => 'block-templates', - 'wp_template_part' => 'block-template-parts', - ); - $themes = array( - get_stylesheet() => get_stylesheet_directory(), - get_template() => get_template_directory(), - ); - foreach ( $themes as $theme_slug => $theme_dir ) { - $file_path = $theme_dir . '/' . $template_base_paths[ $template_type ] . '/' . $slug . '.html'; - if ( file_exists( $file_path ) ) { - $new_template_item = array( - 'slug' => $slug, - 'path' => $file_path, - 'theme' => $theme_slug, - 'type' => $template_type, - ); - return self::gutenberg_add_template_info( $new_template_item ); - } - } - - return null; - } - - /** - * Attempts to add the template part's area information to the input template. - * - * @param array $template_info Template to add information to (requires 'type' and 'slug' fields). - * - * @return array Template. - */ - public static function gutenberg_add_template_part_area_info( $template_info ) { - if ( \WP_Theme_JSON_Resolver_Gutenberg::theme_has_support() ) { - $theme_data = \WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_template_parts(); - } - - if ( isset( $theme_data[ $template_info['slug'] ]['area'] ) ) { - $template_info['title'] = $theme_data[ $template_info['slug'] ]['title']; - $template_info['area'] = gutenberg_filter_template_part_area( $theme_data[ $template_info['slug'] ]['area'] ); - } else { - $template_info['area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED; - } - - return $template_info; - } - /** * Build a unified template object based a post Object. * From 21e08bc3629ea2392277acc7fbbc530e6f85994a Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Fri, 5 Nov 2021 10:39:30 +0000 Subject: [PATCH 15/25] Check if a saved version of the template exists when trying to render --- src/BlockTemplatesController.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index 8f443d48a45..604b9efa2e9 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -291,6 +291,12 @@ public function default_block_template_is_available( $template_name ) { return is_readable( $this->templates_directory . '/' . $template_name . '.html' + ) || + array_filter( + $this->get_block_templates(), + function ( $template ) use ( $template_name ) { + return $template->slug === $template_name; + } ); } From 156cb225f1252d141757e72108a96e63a265ff57 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Fri, 5 Nov 2021 10:40:12 +0000 Subject: [PATCH 16/25] Rename default_block_template_is_available to block_template_is_available --- src/BlockTemplatesController.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index 604b9efa2e9..e08e94c4b8f 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -112,7 +112,7 @@ public function get_single_block_template( $template, $id, $template_type ) { list( , $slug ) = $template_name_parts; // If this blocks template doesn't exist then we should just skip the function and let Gutenberg handle it. - if ( ! $this->default_block_template_is_available( $slug ) ) { + if ( ! $this->block_template_is_available( $slug ) ) { return $template; } @@ -284,7 +284,7 @@ public function theme_has_template( $template_name ) { * @param string $template_name Template to check. * @return boolean */ - public function default_block_template_is_available( $template_name ) { + public function block_template_is_available( $template_name ) { if ( ! $template_name ) { return false; } @@ -311,19 +311,19 @@ public function render_block_template() { if ( is_singular( 'product' ) && ! $this->theme_has_template( 'single-product' ) && - $this->default_block_template_is_available( 'single-product' ) + $this->block_template_is_available( 'single-product' ) ) { add_filter( 'woocommerce_has_block_template', '__return_true', 10, 0 ); } elseif ( is_tax() && ! $this->theme_has_template( 'taxonomy-product_cat' ) && - $this->default_block_template_is_available( 'taxonomy-product_cat' ) + $this->block_template_is_available( 'taxonomy-product_cat' ) ) { add_filter( 'woocommerce_has_block_template', '__return_true', 10, 0 ); } elseif ( ( is_post_type_archive( 'product' ) || is_page( wc_get_page_id( 'shop' ) ) ) && ! $this->theme_has_template( 'archive-product' ) && - $this->default_block_template_is_available( 'archive-product' ) + $this->block_template_is_available( 'archive-product' ) ) { add_filter( 'woocommerce_has_block_template', '__return_true', 10, 0 ); } From e715879fdea1faf74a9750571aa848444bb1a728 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Fri, 5 Nov 2021 12:15:00 +0000 Subject: [PATCH 17/25] Re-hook pre_get_block_template before returning from maybe_return_blocks_template --- src/BlockTemplatesController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index e08e94c4b8f..eca6cbd0377 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -67,6 +67,7 @@ public function maybe_return_blocks_template( $template, $id, $template_type ) { // the slug has not been modified at this point, we're still using the default one passed to this hook. $maybe_template = gutenberg_get_block_template( $id, $template_type ); if ( null !== $maybe_template ) { + add_filter( 'pre_get_block_template', array( $this, 'maybe_return_blocks_template' ), 10, 3 ); return $maybe_template; } From 238560cf8785f531b5aeddac7ecfe039f8a67a18 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Fri, 5 Nov 2021 12:17:05 +0000 Subject: [PATCH 18/25] Make comment easier to read --- src/BlockTemplatesController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index eca6cbd0377..c0638505c76 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -207,7 +207,7 @@ public function get_block_templates() { $template_files = BlockTemplateUtils::gutenberg_get_template_paths( $this->templates_directory ); $templates = array(); - // Check if the template has been saved in the database first. + // First, retrieve the templates which are saved in the database. $check_query_args = array( 'post_type' => 'wp_template', 'posts_per_page' => -1, From 34c33c66de4b28b369c6a8f187e58cb0ba6bc4be Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Fri, 5 Nov 2021 12:18:57 +0000 Subject: [PATCH 19/25] Look for template in woocommerce theme or real theme taxonomy --- src/BlockTemplatesController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index c0638505c76..bda2317f36b 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -216,7 +216,7 @@ public function get_block_templates() { array( 'taxonomy' => 'wp_theme', 'field' => 'name', - 'terms' => 'woocommerce', + 'terms' => array( 'woocommerce', get_stylesheet() ), ), ), ); From 8760a010a065c228c5fa5ce929047c90eb32f385 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Fri, 5 Nov 2021 12:23:07 +0000 Subject: [PATCH 20/25] Remove duplicated title assignment --- src/Utils/BlockTemplateUtils.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Utils/BlockTemplateUtils.php b/src/Utils/BlockTemplateUtils.php index abf1c721e60..dc8ac4189a4 100644 --- a/src/Utils/BlockTemplateUtils.php +++ b/src/Utils/BlockTemplateUtils.php @@ -131,11 +131,10 @@ public static function gutenberg_build_template_result_from_file( $template_file $template->source = 'woocommerce'; $template->slug = $template_file->slug; $template->type = $template_type; - $template->title = ! empty( $template_file->title ) ? $template_file->title : $template_file->slug; + $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->is_custom = false; // Templates loaded from the filesystem aren't custom, ones that have been edited and loaded from the DB are. - $template->title = self::convert_slug_to_title( $template_file->slug ); return $template; } From c83af043bffeab823e72a0a5bad8ebb74ba14d3e Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Fri, 5 Nov 2021 13:14:25 +0000 Subject: [PATCH 21/25] Prevent template being added twice when loading from the db --- src/BlockTemplatesController.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index bda2317f36b..692d7da8f77 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -163,6 +163,19 @@ function ( $template ) use ( $query ) { // @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; + } + ) + ) { + continue; + } + // It would be custom if the template was modified in the editor, so if it's not custom we can load it from // the filesystem. if ( 'custom' !== $template_file->source ) { From 550d218135d30c89ea9e852c99b4f6cb4d2070b3 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Fri, 5 Nov 2021 13:47:57 +0000 Subject: [PATCH 22/25] Filter templates before returning if slugs are supplied --- src/BlockTemplatesController.php | 51 ++++++++++---------------------- 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index 692d7da8f77..d4dc610a6bd 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -117,19 +117,8 @@ public function get_single_block_template( $template, $id, $template_type ) { return $template; } - $available_templates = $this->get_block_templates(); - - // array_values is used to rebase the array back to being 0-indexed. - $matched_templates = array_values( - array_filter( - $available_templates, - function( $available_template ) use ( $slug ) { - $available_template = (object) $available_template; - return $available_template->slug === $slug; - } - ) - ); - return ( is_array( $matched_templates ) && count( $matched_templates ) > 0 ) ? (object) $matched_templates[0] : $template; + $available_templates = $this->get_block_templates( array( $slug ) ); + return ( is_array( $available_templates ) && count( $available_templates ) > 0 ) ? (object) $available_templates[0] : $template; } /** @@ -146,19 +135,8 @@ public function add_block_templates( $query_result, $query, $template_type ) { } $post_type = isset( $query['post_type'] ) ? $query['post_type'] : ''; - $template_files = $this->get_block_templates(); - - if ( isset( $query['slug__in'] ) ) { - // Get only the template files that match the slugs requested in the query. - $template_files = array_values( - array_filter( - $template_files, - function ( $template ) use ( $query ) { - return in_array( $template->slug, $query['slug__in'], true ); - } - ) - ); - } + $slugs = isset( $query['slug__in'] ) ? $query['slug__in'] : array(); + $template_files = $this->get_block_templates( $slugs ); // @todo: Add apply_filters to _gutenberg_get_template_files() in Gutenberg to prevent duplication of logic. foreach ( $template_files as $template_file ) { @@ -214,9 +192,10 @@ function( $query_result_template ) use ( $template_file ) { /** * Get and build the block template objects from the block template files. * + * @param array $slugs An array of slugs to retrieve templates for. * @return array */ - public function get_block_templates() { + public function get_block_templates( $slugs = array() ) { $template_files = BlockTemplateUtils::gutenberg_get_template_paths( $this->templates_directory ); $templates = array(); @@ -278,7 +257,15 @@ function ( $template ) use ( $template_slug ) { ); $templates[] = (object) $new_template_item; } - return $templates; + // Get only the template files that match the slugs requested in the query. + return count( $slugs ) > 0 ? array_values( + array_filter( + $templates, + function ( $template ) use ( $slugs ) { + return in_array( $template->slug, $slugs, true ); + } + ) + ) : $templates; } /** @@ -305,13 +292,7 @@ public function block_template_is_available( $template_name ) { return is_readable( $this->templates_directory . '/' . $template_name . '.html' - ) || - array_filter( - $this->get_block_templates(), - function ( $template ) use ( $template_name ) { - return $template->slug === $template_name; - } - ); + ) || $this->get_block_templates( array( $template_name ) ); } /** From c06a4e5dfb8b2b56f6acfff66266bb38082ab879 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Fri, 5 Nov 2021 15:22:50 +0000 Subject: [PATCH 23/25] Simplify `get_block_templates` function into two functions --- src/BlockTemplatesController.php | 63 ++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index d4dc610a6bd..9d64090b613 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -195,12 +195,8 @@ function( $query_result_template ) use ( $template_file ) { * @param array $slugs An array of slugs to retrieve templates for. * @return array */ - public function get_block_templates( $slugs = array() ) { - $template_files = BlockTemplateUtils::gutenberg_get_template_paths( $this->templates_directory ); - $templates = array(); - - // First, retrieve the templates which are saved in the database. - $check_query_args = array( + public function get_block_templates_from_db( $slugs = array() ) { + $check_query_args = array( 'post_type' => 'wp_template', 'posts_per_page' => -1, 'no_found_rows' => true, @@ -212,14 +208,32 @@ public function get_block_templates( $slugs = array() ) { ), ), ); + if ( is_array( $slugs ) && count( $slugs ) > 0 ) { + $check_query_args['post_name__in'] = $slugs; + } $check_query = new \WP_Query( $check_query_args ); $saved_woo_templates = $check_query->posts; - // From a WordPress post, build the template object and add it to our list. - foreach ( $saved_woo_templates as $saved_woo_template ) { - $templates[] = BlockTemplateUtils::gutenberg_build_template_result_from_post( $saved_woo_template ); - } + return array_map( + function( $saved_woo_template ) { + return BlockTemplateUtils::gutenberg_build_template_result_from_post( $saved_woo_template ); + }, + $saved_woo_templates + ); + } + /** + * Gets the templates from the WooCommerce blocks directory, skipping those for which a template already exists + * in the theme directory. + * + * @param string[] $slugs An array of slugs to filter templates by. Templates whose slug does not match will not be returned. + * @param array $already_found_templates Templates that have already been found, these will customised templates that are loaded from the database. + * + * @return array Templates from the WooCommerce blocks plugin directory. + */ + public function get_block_templates_from_woocommerce( $slugs, $already_found_templates ) { + $template_files = BlockTemplateUtils::gutenberg_get_template_paths( $this->templates_directory ); + $templates = array(); foreach ( $template_files as $template_file ) { $template_slug = substr( $template_file, @@ -227,13 +241,18 @@ public function get_block_templates( $slugs = array() ) { -5 ); + // This template does not have a slug we're looking for. Skip it. + if ( is_array( $slugs ) && count( $slugs ) > 0 && ! in_array( $template_slug, $slugs, true ) ) { + continue; + } + // If the theme already has a template, or the template is already in the list (i.e. it came from the // database) then we should not overwrite it with the one from the filesystem. if ( $this->theme_has_template( $template_slug ) || count( array_filter( - $templates, + $already_found_templates, function ( $template ) use ( $template_slug ) { $template_obj = (object) $template; //phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.Found return $template_obj->slug === $template_slug; @@ -257,15 +276,19 @@ function ( $template ) use ( $template_slug ) { ); $templates[] = (object) $new_template_item; } - // Get only the template files that match the slugs requested in the query. - return count( $slugs ) > 0 ? array_values( - array_filter( - $templates, - function ( $template ) use ( $slugs ) { - return in_array( $template->slug, $slugs, true ); - } - ) - ) : $templates; + return $templates; + } + + /** + * Get and build the block template objects from the block template files. + * + * @param array $slugs An array of slugs to retrieve templates for. + * @return array + */ + public function get_block_templates( $slugs = array() ) { + $templates_from_db = $this->get_block_templates_from_db( $slugs ); + $templates_from_woo = $this->get_block_templates_from_woocommerce( $slugs, $templates_from_db ); + return array_merge( $templates_from_db, $templates_from_woo ); } /** From a365ae825fc9453887554f3a64e2faec8c288d74 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Fri, 5 Nov 2021 15:23:57 +0000 Subject: [PATCH 24/25] Add function to stop theme templates that are added after db ones showing --- src/BlockTemplatesController.php | 46 ++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index 9d64090b613..3fe44a8a9b4 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -186,14 +186,56 @@ function( $query_result_template ) use ( $template_file ) { } } + $query_result = $this->remove_theme_templates_with_custom_alternative( $query_result ); return $query_result; } /** - * Get and build the block template objects from the block template files. + * Removes templates that were added to a theme's block-templates director, but already had a customised version saved in the database. + * + * @param \WP_Block_Template[]|\stdClass[] $templates List of templates to run the filter on. + * + * @return array List of templates with duplicates removed. The customised alternative is preferred over the theme default. + */ + public function remove_theme_templates_with_custom_alternative( $templates ) { + + // Get the slugs of all templates that have been customised and saved in the database. + $customised_template_slugs = array_map( + function( $template ) { + return $template->slug; + }, + array_values( + array_filter( + $templates, + function( $template ) { + // This template has been customised and saved as a post. + return 'custom' === $template->source; + } + ) + ) + ); + + // Remove theme (i.e. filesystem) templates that have the same slug as a customised one. We don't need to check + // for `woocommerce` in $template->source here because woocommerce templates won't have been added to $templates + // if a saved version was found in the db. This only affects saved templates that were saved BEFORE a theme + // template with the same slug was added. + return array_values( + array_filter( + $templates, + function( $template ) use ( $customised_template_slugs ) { + // This template has been customised and saved as a post, so return it. + return ! ( 'theme' === $template->source && in_array( $template->slug, $customised_template_slugs, true ) ); + } + ) + ); + } + + /** + * Gets the templates saved in the database. * * @param array $slugs An array of slugs to retrieve templates for. - * @return array + * + * @return int[]|\WP_Post[] An array of found templates. */ public function get_block_templates_from_db( $slugs = array() ) { $check_query_args = array( From 02dec60c21242f1d48860427e334c0a1dfde1421 Mon Sep 17 00:00:00 2001 From: Thomas Roberts Date: Fri, 5 Nov 2021 19:07:05 +0000 Subject: [PATCH 25/25] Fix typographical errors --- src/BlockTemplatesController.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BlockTemplatesController.php b/src/BlockTemplatesController.php index 3fe44a8a9b4..4c41547eaba 100644 --- a/src/BlockTemplatesController.php +++ b/src/BlockTemplatesController.php @@ -43,7 +43,7 @@ protected function init() { /** * This function checks if there's a blocks template (ultimately it resolves either a saved blocks template from the - * database or a template file in `woo-gutenberg-products/block/templates/block-templates/`) + * database or a template file in `woo-gutenberg-products-block/templates/block-templates/`) * to return to pre_get_posts short-circuiting the query in Gutenberg. * * @param \WP_Block_Template|null $template Return a block template object to short-circuit the default query, @@ -191,7 +191,7 @@ function( $query_result_template ) use ( $template_file ) { } /** - * Removes templates that were added to a theme's block-templates director, but already had a customised version saved in the database. + * Removes templates that were added to a theme's block-templates directory, but already had a customised version saved in the database. * * @param \WP_Block_Template[]|\stdClass[] $templates List of templates to run the filter on. * @@ -269,7 +269,7 @@ function( $saved_woo_template ) { * in the theme directory. * * @param string[] $slugs An array of slugs to filter templates by. Templates whose slug does not match will not be returned. - * @param array $already_found_templates Templates that have already been found, these will customised templates that are loaded from the database. + * @param array $already_found_templates Templates that have already been found, these are customised templates that are loaded from the database. * * @return array Templates from the WooCommerce blocks plugin directory. */