From a73ee64ba91c33bf08910cf2b6a70c808a6077aa Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Sat, 27 Nov 2021 17:24:46 +0100 Subject: [PATCH 1/5] Enable unit test that covers child theme PHP template precedence --- tests/phpunit/tests/block-template.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/phpunit/tests/block-template.php b/tests/phpunit/tests/block-template.php index 94cea83896e85..a712aef8f9b11 100644 --- a/tests/phpunit/tests/block-template.php +++ b/tests/phpunit/tests/block-template.php @@ -92,13 +92,6 @@ function test_more_specific_php_template_takes_precedence_over_less_specific_blo * */ function test_child_theme_php_template_takes_precedence_over_equally_specific_parent_theme_block_template() { - /** - * @todo This test is currently marked as skipped, since it wouldn't pass. Turns out that in Gutenberg, - * it only passed due to a erroneous test setup. - * For details, see https://github.com/WordPress/wordpress-develop/pull/1920#issuecomment-975929818. - */ - $this->markTestSkipped( 'The block template resolution algorithm needs fixing in order for this test to pass.' ); - switch_theme( 'block-theme-child' ); $page_slug_template = 'page-home.php'; From cab0f395283971a58b1a4a69577ad1ed99d88f03 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 29 Nov 2021 14:01:39 +0100 Subject: [PATCH 2/5] Mention Core Trac ticket for regression --- tests/phpunit/tests/block-template.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/phpunit/tests/block-template.php b/tests/phpunit/tests/block-template.php index a712aef8f9b11..95dab825b98a1 100644 --- a/tests/phpunit/tests/block-template.php +++ b/tests/phpunit/tests/block-template.php @@ -89,6 +89,7 @@ function test_more_specific_php_template_takes_precedence_over_less_specific_blo * otherwise equal specificity. * * Covers https://github.com/WordPress/gutenberg/pull/31123. + * Covers https://core.trac.wordpress.org/ticket/54515. * */ function test_child_theme_php_template_takes_precedence_over_equally_specific_parent_theme_block_template() { From 6899d475c871c6cedf374c225376dd7a764e70b1 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 30 Nov 2021 21:15:43 +0100 Subject: [PATCH 3/5] Fix the issue --- src/wp-includes/block-template.php | 43 ++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index 945b96b027422..e363d0d638ac8 100644 --- a/src/wp-includes/block-template.php +++ b/src/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 block matching 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 @@ static function ( $template_a, $template_b ) use ( $slug_priorities ) { } ); + $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 ( 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; } From 5585807a8690cd899997fc4ae226bc6c798aea1a Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 30 Nov 2021 21:18:21 +0100 Subject: [PATCH 4/5] typo --- src/wp-includes/block-template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index e363d0d638ac8..28167f31d437f 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -96,7 +96,7 @@ function locate_block_template( $template, $type, array $templates ) { * * @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 block matching template is found. + * @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, $fallback_template ) { From ba4b5913ddc14316e83b57d2252a7cc6d9ee58c4 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 1 Dec 2021 16:01:45 +0100 Subject: [PATCH 5/5] Make sure we do have a template_file --- src/wp-includes/block-template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index 28167f31d437f..b267c4ea8f345 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -160,7 +160,7 @@ static function ( $template_a, $template_b ) use ( $slug_priorities ) { // -- 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 ( get_template() === $template_file['theme'] ) { + 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 );