函数文档

resolve_block_template()

💡 云策文档标注

概述

resolve_block_template() 函数用于根据请求的模板类型和层级,返回正确的 'wp_template' 块模板对象。它处理模板优先级匹配,并考虑子主题和父主题的 PHP 回退模板。

关键要点

  • 函数接受三个参数:$template_type(模板类型)、$template_hierarchy(模板层级数组)和 $fallback_template(PHP 回退模板路径)。
  • 通过 get_block_templates() 查询匹配的块模板,并按层级优先级排序。
  • 在子主题场景中,如果块模板来自父主题,则优先使用子主题的 PHP 模板。
  • 返回 WP_Block_Template 对象或 null。

代码示例

function resolve_block_template( $template_type, $template_hierarchy, $fallback_template ) {
    if ( ! $template_type ) {
        return null;
    }

    if ( empty( $template_hierarchy ) ) {
        $template_hierarchy = array( $template_type );
    }

    $slugs = array_map(
        '_strip_template_file_suffix',
        $template_hierarchy
    );

    // Find all potential templates 'wp_template' post matching the hierarchy.
    $query     = array(
        'slug__in' => $slugs,
    );
    $templates = get_block_templates( $query );

    // Order these templates per slug priority.
    // Build map of template slugs to their priority in the current hierarchy.
    $slug_priorities = array_flip( $slugs );

    usort(
        $templates,
        static function ( $template_a, $template_b ) use ( $slug_priorities ) {
            return $slug_priorities[ $template_a->slug ] - $slug_priorities[ $template_b->slug ];
        }
    );

    $theme_base_path        = get_stylesheet_directory() . DIRECTORY_SEPARATOR;
    $parent_theme_base_path = get_template_directory() . DIRECTORY_SEPARATOR;

    // Is the active theme a child theme, and is the PHP fallback template part of it?
    if (
        str_starts_with( $fallback_template, $theme_base_path ) &&
        ! str_contains( $fallback_template, $parent_theme_base_path )
    ) {
        $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 active theme's slug by _build_block_template_result_from_file(),
            // even if the block template is really coming from the active theme's parent.
            // (The reason for this is that we want it to be associated with the active 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;
}

注意事项

  • 在 WordPress 5.9.0 中引入了 $fallback_template 参数,用于处理 PHP 回退模板。
  • 函数内部使用 _get_block_template_file() 来准确判断块模板的来源主题,避免因主题关联问题导致错误。
  • 返回的模板对象可能为 null,调用时需进行空值检查。

📄 原文内容

Returns the correct ‘wp_template’ to render for the request template type.

Parameters

$template_typestringrequired
The current template type.
$template_hierarchystring[]required
The current template hierarchy, ordered by priority.
$fallback_templatestringrequired
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.

Source

function resolve_block_template( $template_type, $template_hierarchy, $fallback_template ) {
	if ( ! $template_type ) {
		return null;
	}

	if ( empty( $template_hierarchy ) ) {
		$template_hierarchy = array( $template_type );
	}

	$slugs = array_map(
		'_strip_template_file_suffix',
		$template_hierarchy
	);

	// Find all potential templates 'wp_template' post matching the hierarchy.
	$query     = array(
		'slug__in' => $slugs,
	);
	$templates = get_block_templates( $query );

	// Order these templates per slug priority.
	// Build map of template slugs to their priority in the current hierarchy.
	$slug_priorities = array_flip( $slugs );

	usort(
		$templates,
		static function ( $template_a, $template_b ) use ( $slug_priorities ) {
			return $slug_priorities[ $template_a->slug ] - $slug_priorities[ $template_b->slug ];
		}
	);

	$theme_base_path        = get_stylesheet_directory() . DIRECTORY_SEPARATOR;
	$parent_theme_base_path = get_template_directory() . DIRECTORY_SEPARATOR;

	// Is the active theme a child theme, and is the PHP fallback template part of it?
	if (
		str_starts_with( $fallback_template, $theme_base_path ) &&
		! str_contains( $fallback_template, $parent_theme_base_path )
	) {
		$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 active theme's slug by _build_block_template_result_from_file(),
			// even if the block template is really coming from the active theme's parent.
			// (The reason for this is that we want it to be associated with the active 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;
}

Changelog

Version Description
5.9.0 Added the $fallback_template parameter.
5.8.0 Introduced.