WordPress 如何判断主题是否为 block theme
How WordPress decides a theme is a “block theme”
WordPress 判断主题是否为 block theme,只检查 templates/index.html 或旧版 block-templates/index.html 是否存在且可读。
“区块主题”这个术语在 WordPress 中经常被使用,但就代码层面而言,它究竟意味着什么,一直没有真正弄清楚。
在研究《文章编辑器将全面采用 iframe:WordPress 7.1 之前区块开发者需要了解的事项》时,我了解到测试 WordPress 7.1 Beta 1 的结果可能会让该计划有所软化:核心团队或许不会强制所有人使用 iframe,而可能只对区块主题强制实施;使用 apiVersion 2 或更低版本区块的经典主题则继续保持当前 7.0 的行为。(链接文章详细介绍了 7.0 阶段的完整情况。)
如果确实按这种方式划分,那么“区块主题”的准确定义就 suddenly 变得非常重要。那么,核心代码究竟检查什么?
公开 API 是 wp_is_block_theme(),它只是向当前启用的主题询问:
PHP
// wp-includes/theme.php (guard clause trimmed)
function wp_is_block_theme() {
return wp_get_theme()->is_block_theme();
}而 WP_Theme::is_block_theme() 完整来看只是一项文件存在性检查:
PHP
// wp-includes/class-wp-theme.php (caching trimmed)
public function is_block_theme() {
$paths_to_index_block_template = array(
$this->get_file_path( '/templates/index.html' ),
$this->get_file_path( '/block-templates/index.html' ),
);
foreach ( $paths_to_index_block_template as $path ) {
if ( is_file( $path ) && is_readable( $path ) ) {
return true;
}
}
return false;
}如果主题提供了 index.html 区块模板,它就是“区块主题”,无论该模板位于 templates/,还是位于 block-templates/(5.9 之前的旧位置)。除此之外不会检查任何其他内容。这会带来一些可能令人意外的结果:
theme.json 并不会让你成为区块主题。 图案、区块模板部分或 add_theme_support( 'block-templates' ) 也都不会。一个主题可以采用所有这些“混合式”功能,却仍然被归入这项检查的经典主题一侧,因为测试只会寻找顶层的 index.html 模板。
子主题会继承这一判定结果。 get_file_path() 会先在子主题中查找,找不到时再回退到父主题,因此区块主题的子主题也是区块主题,即使子主题本身没有提供任何模板。
这是一项文件系统检查,而不是声明。 style.css 中没有任何头部信息可让你选择加入或退出。只要把 templates/index.html 放入主题中,就 WordPress 而言,它就是区块主题。
区块主题与经典主题所需的最少文件
这就是一个最小可行的区块主题所需的全部内容——两个文件:
Markdown
my-block-theme/
├── style.css ← standard theme header
└── templates/
└── index.html ← this file IS the decider(如果主题包含 style.css,并且同时具备 index.php 或 templates/index.html 中的任意一个,WordPress 就会认为该主题有效;这意味着对于区块主题而言,index.php、functions.php,甚至 theme.json 都是可选的。)
而以下主题则保证保持为经典主题:
Markdown
my-classic-theme/
├── style.css
└── index.php ← the classic fallback template要在这项检查中保持经典主题一侧,需要满足两个条件:
- 没有
templates/index.html,也没有旧版block-templates/index.html。 其他区块模板无关紧要:一个包含 `templates/single.html` 但没有 `templates/index.html` 的主题,测试结果仍为经典主题。(不过实际上,如果你要提供区块模板,就应同时提供 index 模板,有意识地成为区块主题。) - 没有区块主题父主题。 这项检查会回退到父主题,因此 Twenty Twenty-Five 的子主题无论包含什么内容,都是区块主题。要成为经典主题,整条主题层级链都必须符合条件。
其他一切都不受限制。theme.json、图案、add_theme_support( 'block-template-parts' )` 由插件注册的自定义模板——都不会切换这一判定。图案、add_theme_support( 'block-template-parts' )、由插件注册的自定义模板:都不会切换这一判定。
实际主题的归类情况
对主题目录中当前发布的一些版本运行这项检查所得的结果
| 测试结果为经典主题 | 测试结果为区块主题 |
|---|---|
| Twenty Twenty-One 以及所有更早的默认主题 | Twenty Twenty-Two 以及所有更晚的默认主题 |
Astra、Kadence、Blocksy、Botiga、Sydney、Hello Elementor——全部都提供 theme.json | |
| GeneratePress、Neve、OceanWP、Storefront |
第一栏中的六个主题都提供 theme.json,也就是主打的“区块”功能,但仍然是经典主题,因为该检查从未查看 theme.json
Twenty Twenty 和 OceanWP 又是两个容易踩坑的例子:它们都提供 templates/ 目录,却仍然是经典主题,因为该目录中充满了 PHP 页面模板(template-cover.php、landing.php)。这项检查 specifically 要求的是 templates/index.html,所以“它是否有一个 templates 文件夹”并不是你可能以为的判断依据。
编辑器如何读取它
在 JavaScript 端,区块主题标志会在两个不同的地方出现;如果你准备深入查看源码,这一点值得了解。
作为编辑器设置:
PHP
// wp-includes/block-editor.php, get_block_editor_settings()
$editor_settings['__unstableIsBlockBasedTheme'] = wp_is_block_theme();以及在 REST 主题端点上,@wordpress/core-data 正是在那里读取它:
PHP
// wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php
$data['is_block_theme'] = $theme->is_block_theme();单文件开关
尽管“区块主题”这个术语听起来分量十足,但它归根结底取决于一个文件:templates/index.html 存在,或者不存在。不是 theme.json,不是 patterns,也不是任何程度的混合式采用。就是一个索引模板,并且会沿父主题链向上检查。
如果 7.1 最终确实把 iframe 的分界线划在 wp_is_block_theme() 上,这一点就值得记住。一个已经采用了所有内容、除了区块模板的混合式主题,仍会保留经典编辑器的行为;而仅仅添加一个 templates/index.html(哪怕是误加,甚至是在你无法控制的父主题中)就会让站点切换为强制使用 iframe。如果你的主题或用户的站点处于这条线附近,现在正是检查自己实际上站在哪一边的好时机:只需一次 is_file() 调用即可确认。
来源:Gutenberg Times(区块编辑器) · https://gutenbergtimes.com/how-wordpress-decides-a-theme-is-a-block-theme/
部分链接为推广/关联链接。