Make WordPress Core


Ignore:
Timestamp:
12/02/2021 11:35:20 PM (3 years ago)
Author:
audrasjb
Message:

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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/block-template.php

    r51657 r52308  
    4646    }
    4747
    48     $block_template = resolve_block_template( $type, $templates );
     48    $block_template = resolve_block_template( $type, $templates, $template );
    4949
    5050    if ( $block_template ) {
     
    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 ) {
     102function resolve_block_template( $template_type, $template_hierarchy, $fallback_template ) {
    101103    if ( ! $template_type ) {
    102104        return null;
     
    129131        }
    130132    );
     133
     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    }
    131170
    132171    return count( $templates ) ? $templates[0] : null;
Note: See TracChangeset for help on using the changeset viewer.