From ddfe23a9aac6b9c6000e242d22c338344f5d72b8 Mon Sep 17 00:00:00 2001 From: audrasjb Date: Thu, 2 Dec 2021 23:36:59 +0000 Subject: [PATCH] Editor: Allow child theme PHP templates to take precedence over parent theme block templates. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change fixes template resolution to give precedence to child theme PHP templates over parent theme block templates with equal specificity. Before this change, when a theme was using a PHP template of a certain specificity (e.g. `page-home.php`), and it happened to be a child theme of another theme which had a block template for the same specificity (e.g. `page-home.html`), WordPress was picking the parent theme’s block template over the child theme’s PHP template to render the page. If the PHP and block template have equal specificity, the child theme's template should be used. The issue was fixed before in Gutenberg so the fix now needs to happen in Core. This change also re-enables the preexisting template resolution unit tests. Follow-up to [51003]. Props bernhard-reiter, youknowriad. Fixes #54515. Built from https://develop.svn.wordpress.org/trunk@52308 git-svn-id: http://core.svn.wordpress.org/trunk@51900 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/block-template.php | 43 ++++++++++++++++++++++++++++++++-- wp-includes/version.php | 2 +- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/wp-includes/block-template.php b/wp-includes/block-template.php index 945b96b027..b267c4ea8f 100644 --- a/wp-includes/block-template.php +++ b/wp-includes/block-template.php @@ -45,7 +45,7 @@ function locate_block_template( $template, $type, array $templates ) { $templates = array_slice( $templates, 0, $index + 1 ); } - $block_template = resolve_block_template( $type, $templates ); + $block_template = resolve_block_template( $type, $templates, $template ); if ( $block_template ) { if ( empty( $block_template->content ) && is_user_logged_in() ) { @@ -92,12 +92,14 @@ function locate_block_template( $template, $type, array $templates ) { * * @access private * @since 5.8.0 + * @since 5.9.0 Added the `$fallback_template` parameter. * * @param string $template_type The current template type. * @param string[] $template_hierarchy The current template hierarchy, ordered by priority. + * @param string $fallback_template A PHP fallback template to use if no matching block template is found. * @return WP_Block_Template|null template A template object, or null if none could be found. */ -function resolve_block_template( $template_type, $template_hierarchy ) { +function resolve_block_template( $template_type, $template_hierarchy, $fallback_template ) { if ( ! $template_type ) { return null; } @@ -129,6 +131,43 @@ function resolve_block_template( $template_type, $template_hierarchy ) { } ); + $theme_base_path = get_stylesheet_directory() . DIRECTORY_SEPARATOR; + $parent_theme_base_path = get_template_directory() . DIRECTORY_SEPARATOR; + + // Is the current theme a child theme, and is the PHP fallback template part of it? + if ( + strpos( $fallback_template, $theme_base_path ) === 0 && + strpos( $fallback_template, $parent_theme_base_path ) === false + ) { + $fallback_template_slug = substr( + $fallback_template, + // Starting position of slug. + strpos( $fallback_template, $theme_base_path ) + strlen( $theme_base_path ), + // Remove '.php' suffix. + -4 + ); + + // Is our candidate block template's slug identical to our PHP fallback template's? + if ( + count( $templates ) && + $fallback_template_slug === $templates[0]->slug && + 'theme' === $templates[0]->source + ) { + // Unfortunately, we cannot trust $templates[0]->theme, since it will always + // be set to the current theme's slug by _build_block_template_result_from_file(), + // even if the block template is really coming from the current theme's parent. + // (The reason for this is that we want it to be associated with the current theme + // -- not its parent -- once we edit it and store it to the DB as a wp_template CPT.) + // Instead, we use _get_block_template_file() to locate the block template file. + $template_file = _get_block_template_file( 'wp_template', $fallback_template_slug ); + if ( $template_file && get_template() === $template_file['theme'] ) { + // The block template is part of the parent theme, so we + // have to give precedence to the child theme's PHP template. + array_shift( $templates ); + } + } + } + return count( $templates ) ? $templates[0] : null; } diff --git a/wp-includes/version.php b/wp-includes/version.php index 228f7a0322..f53901ff86 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '5.9-beta1-52307'; +$wp_version = '5.9-beta1-52308'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.