Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FSE: Fix template resolution to give precedence to child theme PHP templates over parent theme block templates with equal specificity #37074

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 42 additions & 2 deletions lib/full-site-editing/template-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function gutenberg_override_query_template( $template, $type, array $templates )
$templates = array_slice( $templates, 0, $index + 1 );
}

$block_template = gutenberg_resolve_template( $type, $templates );
$block_template = gutenberg_resolve_template( $type, $templates, $template );

if ( $block_template ) {
if ( empty( $block_template->content ) && is_user_logged_in() ) {
Expand Down Expand Up @@ -109,11 +109,14 @@ function gutenberg_override_query_template( $template, $type, array $templates )
*
* Accepts an optional $template_hierarchy argument as a hint.
*
* @since 5.9.0 Added the `$fallback_template` parameter.
*
* @param string $template_type The current template type.
* @param string[] $template_hierarchy (optional) 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 null|Gutenberg_Block_Template A block template if found. Null if not.
*/
function gutenberg_resolve_template( $template_type, $template_hierarchy ) {
function gutenberg_resolve_template( $template_type, $template_hierarchy, $fallback_template ) {
if ( ! $template_type ) {
return null;
}
Expand Down Expand Up @@ -145,6 +148,43 @@ 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 ( $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;
}

Expand Down