相比模板和模板组件这类功能,模式的最大优势之一在于可以在其中使用 PHP,这为实现各种功能带来了无限可能。不过,模式所能具备的功能仍存在一定的限制。
在本文中,您将了解模式系统的局限性、何时以及如何使用 PHP,以及一些实现动态功能的常见用例。
模式在初始化时注册
在模式中使用 PHP 时,重要的是要明白模式的块标记实际上是在何时被编译,又是在何时被渲染的。
模式的注册发生在 init 钩子中。此时,WordPress 会编译模式的内容,并将其保存为基于 HTML 的块标记副本,这样它就可以在编辑器和前端使用。正是在这个注册过程中,模式才能执行 PHP 代码。
模式的块标记实际上要等到在编辑器或前端被使用时才会被渲染。不过,在渲染时这些块标记仍是普通的 HTML。
从实际应用角度来看,这意味着在 init 阶段的注册过程中,很多数据是不可用的。您的模式无法访问全局查询或文章之类的内容,也无法使用与这些数据相关的函数。因此,像 is_home()、is_single()、get_post() 这样的 WordPress 函数在当时还不可用。
例如,以下 PHP 代码在模式中无法正确执行:
<?php if ( is_page() ) : ?>
<!-- wp:paragraph -->
<p><?php the_title(); ?></p>
<!-- /wp:paragraph -->
<?php endif; ?>在模式注册时,is_page() 和 the_title() 函数都无法获取它们所需的全局数据,因此无法正常工作。
如果您习惯于构建传统主题,这种方式可能会让您觉得很不直观,尤其是当您将基于 PHP 的模式与传统的基于 PHP 的模板组件相混淆时。
在渲染时执行 PHP 还有其他方法,比如使用 块绑定 API。但这些方法不在模式文档的讨论范围内。
实际上,您仍然可以使用大量丰富的 PHP 函数以及许多 WordPress 函数。在本文的后续章节中,您将了解到更多关于您可以使用哪些功能的内容。
一个示例模式
在本文的剩余部分,我们将使用一个主要以 HTML 形式构成的模式,然后您将了解如何添加 PHP 代码来动态处理其中的部分内容。
在您的主题中创建一个名为 patterns/hero.php 的新文件,并将以下代码放入其中:
<?php
/**
* Title: Hero
* Slug: themeslug/hero
* Categories: featured
*/
?>
<!-- wp:cover {"overlayColor":"contrast","isUserOverlayColor":true,"align":"full"} -->
<div class="wp-block-cover alignfull">
<span aria-hidden="true" class="wp-block-cover__background has-contrast-background-color has-background-dim-100 has-background-dim"></span>
<div class="wp-block-cover__inner-container">
<!-- wp:heading {"textAlign":"center"} -->
<h2 class="wp-block-heading has-text-align-center">欢迎来到我的网站</h2>
<!-- /wp:heading -->
<!-- wp:paragraph {"align":"center"} -->
<p class="has-text-align-center">这是我的小小家园。</p>
<!-- /wp:paragraph -->
<!-- wp:buttons {"layout":{"type":"flex","justifyContent":"center"}} -->
<div class="wp-block-buttons">
<!-- wp:button {"className":"wp-block-button is-style-outline"} -->
<div class="wp-block-button is-style-outline"><a class="wp-block-button__link wp-element-button">按钮 A</a></div>
<!-- /wp:button -->
<!-- wp:button {"className":"wp-block-button is-style-outline"} -->
<div class="wp-block-button is-style-outline"><a class="wp-block-button__link wp-element-button">按钮 B</a></div>
<!-- /wp:button -->
</div>
<!-- /wp:buttons -->
</div>
</div>
<!-- /wp:cover -->如果将此模式插入编辑器,它应该看起来像这样:

在模式中实现文本国际化
块模式的主要用途之一就是实现文本国际化(即为翻译做好准备)。例如,如果模板或模板组件中包含文本,要实现文本国际化,唯一的方法就是将其移到模式中,因为在模式中您可以完全使用 PHP。
由于模式文件本身就是 PHP 代码,因此您可以使用 WordPress 中的任何国际化函数。在下面的示例中,您将使用 esc_html_e() 来同时确保文本的安全性并使其适合翻译人员处理。
让我们来看看您刚才的 Hero 模式中的 Heading 块:
<!-- wp:heading {"textAlign":"center"} -->
<h2 class="wp-block-heading has-text-align-center">>欢迎来到我的网站</h2>
<!-- /wp:heading -->如您所见,Heading 块中的“欢迎来到我的网站”文本并未实现国际化。当您将主题发布给使用多种语言的全世界用户时,确保这段文本可以被翻译非常重要。
要实现 Heading 块文本的国际化,必须将其包裹在国际化函数中(本例中为 esc_html_e())。因此,您需要将块标记修改为如下形式:
<!-- wp:heading {"textAlign":"center"} -->
<h2 class="wp-block-heading has-text-align-center"><?php esc_html_e( 'Welcome to My Site', 'themeslug' ); ?></h2>
<!-- /wp:heading -->还有另外三个地方也需要进行同样的修改:首先是 Paragraph 块的文本,然后是两个 Button 块。修改后的 patterns/hero.php 文件应该看起来像这样:
<?php
/**
* Title: Hero
* Slug: themeslug/hero
* Categories: featured
*/
?>
<!-- wp:cover {"overlayColor":"contrast","isUserOverlayColor":true,"align":"full"} -->
<div class="wp-block-cover alignfull">
<span aria-hidden="true" class="wp-block-cover__background has-contrast-background-color has-background-dim-100 has-background-dim"></span>
<div class="wp-block-cover__inner-container">
<!-- wp:heading {"textAlign":"center"} -->
<h2 class="wp-block-heading has-text-align-center"><?php esc_html_e( 'Welcome to My Site', 'themeslug' ); ?></h2>
<!-- /wp:heading -->
<!-- wp:paragraph {"align":"center"} -->
<p class="has-text-align-center"><?php esc_html_e( 'This is my little home away from home.', 'themeslug' ); ?></p>
<!-- /wp:paragraph -->
<!-- wp:buttons {"layout":{"type":"flex","justifyContent":"center"}} -->
<div class="wp-block-buttons">
<!-- wp:button {"className":"wp-block-button is-style-outline"} -->
<div class="wp-block-button is-style-outline"><a class="wp-block-button__link wp-element-button"><?php esc_html_e( 'Button A', 'themeslug' ); ?></a></div>
<!-- /wp:button -->
<!-- wp:button {"className":"wp-block-button is-style-outline"} -->
<div class="wp-block-button is-style-outline"><a class="wp-block-button__link wp-element-button"><?php esc_html_e( 'Button B', 'themeslug' ); ?></a></div>
<!-- /wp:button -->
</div>
<!-- /wp:buttons -->
</div>
</div>
<!-- /wp:cover -->使用图片及其他资源
为图片及其他资源添加动态 URL 是模式的另一项重要功能。由于您可以使用 PHP,因此可以运用诸如 get_theme_file_uri() 这样的函数来输出与您的主题一同打包的图片 URL。
试着在“hero”模式的 Cover 块中添加图片背景。如果您需要图片,可以尝试从 WordPress 的 图片库 中获取图片(下面的示例使用了 尼泊尔夜景图片)。
下载一张图片并将其保存到主题的 /assets/images 文件夹中(或您选择的任意文件夹),并将其命名为 hero-background.jpg。
然后在编辑器中打开该模式,并将这张图片上传作为 Hero 模式中 Cover 块的背景,它应该看起来像这样:

如果您复制构成该模式的各个块,会发现模式代码中出现了两个图片 URL。它们会是类似如下的硬编码 URL:
http://localhost/wp-content/uploads/2023/10/hero-background.jpg您需要修改这两个 URL,使其指向位于主题 /assets/images 文件夹中的图片。为此,需要做两件事:
- 使用如
get_theme_file_uri()这样的函数获取正确的 URL。 - 使用
esc_url()对 URL 进行转义,以确保其能够安全地被输出。
将硬编码的图片 URL 更改为如下形式:
<?php echo esc_url( get_theme_file_uri( 'assets/images/hero-background.jpg' ) ); ?>最终的模式代码应该看起来像这样(请注意,此示例包含了前文提到的国际化文本及动态图片的代码):
<?php
/**
* Title: Hero
* Slug: themeslug/hero
* Categories: featured
*/
?>
<!-- wp:cover {"url":"<?php echo esc_url( get_theme_file_uri( 'assets/images/hero-background.jpg' ) ); ?>","id":3838,"dimRatio":50,"overlayColor":"contrast","align":"full"} -->
<div class="wp-block-cover alignfull">
<span aria-hidden="true" class="wp-block-cover__background has-contrast-background-color has-background-dim"></span>
<img class="wp-block-cover__image-background wp-image-3838" alt="" src="<?php echo esc_url( get_theme_file_uri( 'assets/images/hero-background.jpg' ) ); ?>" data-object-fit="cover"/>
<div class="wp-block-cover__inner-container">
<!-- wp:heading {"textAlign":"center"} -->
<h2 class="wp-block-heading has-text-align-center"><?php esc_html_e( 'Welcome to My Site', 'themeslug' ); ?></h2>
<!-- /wp:heading -->
<!-- wp:paragraph {"align":"center"} -->
<p class="has-text-align-center"><?php esc_html_e( 'This is my little home away from home.', 'themeslug' ); ?></p>
<!-- /wp:paragraph -->
<!-- wp:buttons {"layout":{"type":"flex","justifyContent":"center"}} -->
<div class="wp-block-buttons">
<?php foreach ( $buttons as $button ) : ?>
<!-- wp:button {"className":"wp-block-button is-style-outline"} -->
<div class="wp-block-button is-style-outline"><a class="wp-block-button__link wp-element-button"><?php echo esc_html( $button ); ?></a></div>
<!-- /wp:button -->
<?php endforeach; ?>
</div>
<!-- /wp:buttons -->
</div>
</div>
<!-- /wp:cover -->foreach() 循环
您几乎可以使用所有的 PHP 函数和功能,而在构建主题的过程中,这些功能无疑会派上用场。不过,foreach() 循环很可能是您会经常使用的功能之一。
foreach() 循环在包含重复块的模式中尤为有用。例如,在您的 patterns/hero.php 文件中,就有两组 Button 块:
<!-- wp:button {"className":"wp-block-button is-style-outline"} -->
<div class="wp-block-button is-style-outline"><a class="wp-block-button__link wp-element-button"><?php esc_html_e( 'Button A', 'themeslug' ); ?></a></div>
<!-- /wp:button -->
<!-- wp:button {"className":"wp-block-button is-style-outline"} -->
<div class="wp-block-button is-style-outline"><a class="wp-block-button__link wp-element-button"><?php esc_html_e( 'Button B', 'themeslug' ); ?></a></div>
<!-- /wp:button -->开发领域的核心原则之一是 DRY(不要重复自己)。而这段代码违背了这一原则。通过使用一个 foreach() 循环,您只需创建一次块标记,然后通过循环来重复使用它。
首先,您需要一个用于循环的数组,也就是按钮的内容。在 patterns/hero.php 文件的顶端、闭合的 ?> 标签之前,添加一个包含标签的数组:
$buttons = array(
__( 'Button A', 'themeslug' ),
__( 'Button B', 'themeslug' )
);然后用以下代码替换两个 Button 块的标记:
<?php foreach ( $buttons as $button ) : ?>
<!-- wp:button {"className":"wp-block-button is-style-outline"} -->
<div class="wp-block-button is-style-outline"><a class="wp-block-button__link wp-element-button"><?php echo esc_html( $button ); ?></a></div>
<!-- /wp:button -->
<?php endforeach; ?>此时,您的模式就完全具备了动态功能。随着您对模式开发的深入,将会发现更多使用 PHP 的可能性。可以把这篇文章视为您后续开发的基础。