Skip to content

Commit d2b043b

Browse files
committed
Editor: Allow child theme PHP templates to take precedence over parent theme block templates.
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. git-svn-id: https://develop.svn.wordpress.org/trunk@52308 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 30ed9e8 commit d2b043b

2 files changed

Lines changed: 42 additions & 9 deletions

File tree

src/wp-includes/block-template.php

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ function locate_block_template( $template, $type, array $templates ) {
4545
$templates = array_slice( $templates, 0, $index + 1 );
4646
}
4747

48-
$block_template = resolve_block_template( $type, $templates );
48+
$block_template = resolve_block_template( $type, $templates, $template );
4949

5050
if ( $block_template ) {
5151
if ( empty( $block_template->content ) && is_user_logged_in() ) {
@@ -92,12 +92,14 @@ function locate_block_template( $template, $type, array $templates ) {
9292
*
9393
* @access private
9494
* @since 5.8.0
95+
* @since 5.9.0 Added the `$fallback_template` parameter.
9596
*
9697
* @param string $template_type The current template type.
9798
* @param string[] $template_hierarchy The current template hierarchy, ordered by priority.
99+
* @param string $fallback_template A PHP fallback template to use if no matching block template is found.
98100
* @return WP_Block_Template|null template A template object, or null if none could be found.
99101
*/
100-
function resolve_block_template( $template_type, $template_hierarchy ) {
102+
function resolve_block_template( $template_type, $template_hierarchy, $fallback_template ) {
101103
if ( ! $template_type ) {
102104
return null;
103105
}
@@ -129,6 +131,43 @@ static function ( $template_a, $template_b ) use ( $slug_priorities ) {
129131
}
130132
);
131133

134+
$theme_base_path = get_stylesheet_directory() . DIRECTORY_SEPARATOR;
135+
$parent_theme_base_path = get_template_directory() . DIRECTORY_SEPARATOR;
136+
137+
// Is the current theme a child theme, and is the PHP fallback template part of it?
138+
if (
139+
strpos( $fallback_template, $theme_base_path ) === 0 &&
140+
strpos( $fallback_template, $parent_theme_base_path ) === false
141+
) {
142+
$fallback_template_slug = substr(
143+
$fallback_template,
144+
// Starting position of slug.
145+
strpos( $fallback_template, $theme_base_path ) + strlen( $theme_base_path ),
146+
// Remove '.php' suffix.
147+
-4
148+
);
149+
150+
// Is our candidate block template's slug identical to our PHP fallback template's?
151+
if (
152+
count( $templates ) &&
153+
$fallback_template_slug === $templates[0]->slug &&
154+
'theme' === $templates[0]->source
155+
) {
156+
// Unfortunately, we cannot trust $templates[0]->theme, since it will always
157+
// be set to the current theme's slug by _build_block_template_result_from_file(),
158+
// even if the block template is really coming from the current theme's parent.
159+
// (The reason for this is that we want it to be associated with the current theme
160+
// -- not its parent -- once we edit it and store it to the DB as a wp_template CPT.)
161+
// Instead, we use _get_block_template_file() to locate the block template file.
162+
$template_file = _get_block_template_file( 'wp_template', $fallback_template_slug );
163+
if ( $template_file && get_template() === $template_file['theme'] ) {
164+
// The block template is part of the parent theme, so we
165+
// have to give precedence to the child theme's PHP template.
166+
array_shift( $templates );
167+
}
168+
}
169+
}
170+
132171
return count( $templates ) ? $templates[0] : null;
133172
}
134173

tests/phpunit/tests/block-template.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,16 +89,10 @@ function test_more_specific_php_template_takes_precedence_over_less_specific_blo
8989
* otherwise equal specificity.
9090
*
9191
* Covers https://github.com/WordPress/gutenberg/pull/31123.
92+
* Covers https://core.trac.wordpress.org/ticket/54515.
9293
*
9394
*/
9495
function test_child_theme_php_template_takes_precedence_over_equally_specific_parent_theme_block_template() {
95-
/**
96-
* @todo This test is currently marked as skipped, since it wouldn't pass. Turns out that in Gutenberg,
97-
* it only passed due to a erroneous test setup.
98-
* For details, see https://github.com/WordPress/wordpress-develop/pull/1920#issuecomment-975929818.
99-
*/
100-
$this->markTestSkipped( 'The block template resolution algorithm needs fixing in order for this test to pass.' );
101-
10296
switch_theme( 'block-theme-child' );
10397

10498
$page_slug_template = 'page-home.php';

0 commit comments

Comments
 (0)