From 8bedbcd2a9f3f673bd5c7816cd349dc63cef7ea6 Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Fri, 7 Mar 2025 17:53:37 +0000 Subject: [PATCH] Editor: Fix unexpected behavior due to conflicting custom block template. This changeset fixes both a visual and functional bug related to template selection in the editor that occurred when having a custom block template registered that was using the same slug as another block template already registered by the theme, including the default block templates. Props aljullu, antonvlasenko, apermo, audrasjb, azaozz, ntsekouras. Fixes #62319. git-svn-id: https://develop.svn.wordpress.org/trunk@59951 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/block-template-utils.php | 30 +++++++++- .../tests/blocks/getBlockTemplates.php | 60 +++++++++++++++++++ 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php index 89ccada17e..faea7d5e83 100644 --- a/src/wp-includes/block-template-utils.php +++ b/src/wp-includes/block-template-utils.php @@ -1185,9 +1185,35 @@ function get_block_templates( $query = array(), $template_type = 'wp_template' ) * over the theme-provided ones, so we skip querying and building them. */ $query['slug__not_in'] = wp_list_pluck( $query_result, 'slug' ); - $template_files = _get_block_templates_files( $template_type, $query ); + /* + * We need to unset the post_type query param because some templates + * would be excluded otherwise, like `page.html` when looking for + * `page` templates. We need all templates so we can exclude duplicates + * from plugin-registered templates. + * See: https://github.com/WordPress/gutenberg/issues/65584 + */ + $template_files_query = $query; + unset( $template_files_query['post_type'] ); + $template_files = _get_block_templates_files( $template_type, $template_files_query ); foreach ( $template_files as $template_file ) { - $query_result[] = _build_block_template_result_from_file( $template_file, $template_type ); + // If the query doesn't specify a post type, or it does and the template matches the post type, add it. + if ( + ! isset( $query['post_type'] ) || + ( + isset( $template_file['postTypes'] ) && + in_array( $query['post_type'], $template_file['postTypes'], true ) + ) + ) { + $query_result[] = _build_block_template_result_from_file( $template_file, $template_type ); + } elseif ( ! isset( $template_file['postTypes'] ) ) { + // The custom templates with no associated post types are available for all post types as long + // as they are not default templates. + $candidate = _build_block_template_result_from_file( $template_file, $template_type ); + $default_template_types = get_default_block_template_types(); + if ( ! isset( $default_template_types[ $candidate->slug ] ) ) { + $query_result[] = $candidate; + } + } } if ( 'wp_template' === $template_type ) { diff --git a/tests/phpunit/tests/blocks/getBlockTemplates.php b/tests/phpunit/tests/blocks/getBlockTemplates.php index 4db9093aae..791f449a16 100644 --- a/tests/phpunit/tests/blocks/getBlockTemplates.php +++ b/tests/phpunit/tests/blocks/getBlockTemplates.php @@ -228,4 +228,64 @@ class Tests_Blocks_GetBlockTemplates extends WP_UnitTestCase { ), ); } + + /** + * @dataProvider data_get_block_templates_should_not_leak_plugin_registered_templates_with_default_post_type_slugs + * @ticket 62319 + * + * @covers ::get_block_templates + * + * @param string $template_slug Default slug for the post type. + * @param string $post_type Post type for query. + * @param array $expected Expected template IDs. + */ + public function test_get_block_templates_should_not_leak_plugin_registered_templates_with_default_post_type_slugs( $template_slug, $post_type, $expected ) { + $template_name = 'test-plugin//' . $template_slug; + $template_args = array( + 'content' => 'Template content', + 'title' => 'Test Template for ' . $post_type, + 'description' => 'Description of test template', + 'post_types' => array( $post_type ), + ); + register_block_template( $template_name, $template_args ); + + $templates = get_block_templates( array( 'post_type' => $post_type ) ); + + $this->assertSameSets( + $expected, + $this->get_template_ids( $templates ) + ); + + unregister_block_template( $template_name ); + } + + /** + * Data provider. + * + * Make sure that plugin-registered templates with default post type slugs (ie: `single` or `page`) + * don't leak into `get_block_templates()`. + * See: https://core.trac.wordpress.org/ticket/62319. + * + * @return array + */ + public function data_get_block_templates_should_not_leak_plugin_registered_templates_with_default_post_type_slugs() { + return array( + 'post' => array( + 'template_slug' => 'single', + 'post_type' => 'post', + 'expected' => array( + 'block-theme//custom-hero-template', + 'block-theme//custom-single-post-template', + ), + ), + 'page' => array( + 'template_slug' => 'page', + 'post_type' => 'page', + 'expected' => array( + 'block-theme//custom-hero-template', + 'block-theme//page-home', + ), + ), + ); + } }