博客

仅用 PHP 创建自定义区块。告别旧式短代码 🥳

David Wang
作者:David Wang ·

自 WordPress 5.0 引入区块编辑器以来,构建 Gutenberg 区块一直需要 React、Node.js 和构建流水线。如果您擅长 PHP——就像我和大多数 WordPress 开发者一样——这道门槛几乎让人在门外徘徊了近十年。WordPress 7.0 改变了这一切。纯 PHP 区块让您只需一个 PHP 文件和 autoRegister 标志,即可注册一个功能完整的 Gutenberg 区块。

您写 PHP,就能得到一个区块。无需工具,无需构建。🥳 本文将介绍纯 PHP 区块的工作原理,并通过一个实际示例演示如何用区块替代传统短代码。

什么是纯 PHP 区块?

过去,创建自定义 Gutenberg 区块意味着要搭建 JavaScript 工具链:npm installblock.json 文件、webpack.config.js@wordpress/scripts 构建步骤,以及用 JSX 编写的 edit.js 组件。每次修改都需要先编译才能在编辑器中预览。对于只想注册一个简单展示区块的 PHP 开发者来说,这些开销与任务本身完全不成比例。

纯 PHP 区块彻底解决了这个问题。现在,在 register_block_type() 中只需传入 'autoRegister' => true,WordPress 就会使用 ServerSideRender 自动处理 JavaScript 端的所有事情。区块会出现在插入器中,在画布上渲染实时预览,并在侧边栏生成检查器控件——这一切无需您编写一行 JavaScript 代码。

控件根据属性类型自动生成:

属性类型生成的检查器控件
string文本输入
integer / number数字输入
boolean开关
string + enum下拉选择

目前自动生成的控件仅涵盖以上四种类型。图片选择器、媒体上传或嵌套数据等更复杂的功能暂不支持,仍需使用 JavaScript 注册的区块。开发者也可以为单个属性标记 local 角色,将其标识为内部状态;WordPress 在构建侧边栏控件时会跳过这些属性。

纯 PHP 区块无需任何额外依赖,今天就可以在 WordPress 7.0 中使用。更多信息请参阅 Make WordPress Core 上的官方开发者说明

这适合哪些人?

缺乏深厚 JavaScript 专业知识的小型机构和自由职业者,现在无需接触构建流水线,就能构建充分利用 WordPress 原生功能的区块编辑器解决方案。如果您想提供主题专属的 Gutenberg 自定义区块,如作者简介框、引文框、用户评价、CTA 横幅、公告等,而不是依赖短代码,纯 PHP 区块将大大降低这一门槛。

当您需要内联富文本编辑、实时响应式 UI 或内部区块嵌套时,它无法替代 JavaScript 注册的区块——但对于大量结构化展示区块来说,它恰好是最佳选择。

旧方式:短代码

在纯 PHP 区块出现之前,PHP 开发者的实用方案是短代码。以下是一个包含三个属性的简单评价短代码:作者姓名、公司名称、星级评分,加上评论正文的内部内容:

function testimonial_shortcode( $atts, $content = '' ) {
    $atts = shortcode_atts( [
        'name'    => '',
        'company' => '',
        'stars'   => 5,
    ], $atts );
 
    $stars_count = max( 1, min( 5, intval( $atts['stars'] ) ) );
    $stars_html  = str_repeat( '★', $stars_count )
                 . str_repeat( '☆', 5 - $stars_count );
 
    return sprintf(
        '<blockquote class="testimonial">
            <p class="testimonial__stars">%s</p>
            <p class="testimonial__body">%s</p>
            <footer class="testimonial__attribution">
                <strong>%s</strong>%s
            </footer>
        </blockquote>',
        esc_html( $stars_html ),
        wp_kses_post( $content ),
        esc_html( $atts['name'] ),
        $atts['company'] ? ', ' . esc_html( $atts['company'] ) : ''
    );
}
add_shortcode( 'testimonial', 'testimonial_shortcode' );

使用方式:

[testimonial name="Sarah K." company="Acme Corp" stars="4"]
	Saved us hours every week.
[/testimonial]

它能用……但也只是个短代码而已 🤷🏻‍♂️

短代码存在诸多问题,列举如下:

  • 在编辑器中不可见。 作者在编辑器中看到的是 [testimonial name="Sarah K." ...],而不是渲染后的卡片。没有预览。
  • 不易发现。 您必须知道短代码的存在,还要记住它的参数名称。UI 中没有任何提示。
  • 没有原生样式控件。 调整颜色、间距或字体需要自定义 CSS 或手动添加额外属性。
  • 内部内容不是富文本。 评论正文通过 $content 作为纯字符串传入——而不是可编辑的富文本区域。

短代码是那个时代的正确工具。区块编辑器提供了更好的选择,但一直难以利用。WordPress 7.0 以纯 PHP 区块的形式提供了一条捷径。

明确一点:构建 Gutenberg 区块的正确新方式仍然是带有完整 edit 组件的 JavaScript 注册区块。纯 PHP 区块是一条简化路径——特意限定于不需要画布内富文本编辑的服务器渲染区块。它们不是 JavaScript 区块的替代品,而是针对更简单用例的新选项,适用于构建流水线和 React 组件的开销不值得的场景。

更简单的选择:纯 PHP 区块

让我们仅用 PHP 将同样的评价构建为 WordPress 自定义区块。方法是:在 supports 中设置 'autoRegister' => trueregister_block_type(),加上 render_callback

以下是区块的完整代码:

function my_plugin_register_testimonial_block() {
    register_block_type(
        'my-plugin/testimonial', // Block name: namespace/slug
        array(
            'title'      => 'Testimonial', // Shown in the block inserter
            'attributes' => array(
                // string attributes generate a text input in the sidebar
                'name'    => array(
                    'type'    => 'string',
                    'default' => '',
                ),
                'company' => array(
                    'type'    => 'string',
                    'default' => '',
                ),
                // integer attributes generate a number input
                'stars'   => array(
                    'type'    => 'integer',
                    'default' => 5,
                ),
                'body'    => array(
                    'type'    => 'string',
                    'default' => '',
                ),
            ),
            // render_callback is the PHP function that outputs the block's HTML
            'render_callback' => function ( $attributes ) {
                $stars_count = max( 1, min( 5, intval( $attributes['stars'] ) ) );
                $stars_html  = str_repeat( '★', $stars_count )
                             . str_repeat( '☆', 5 - $stars_count );
 
                // Translatable string for screen readers — standard WordPress i18n, nothing extra needed
                /* translators: %d: star rating out of 5 */
                $stars_label = sprintf( __( '%d out of 5 stars', 'my-plugin' ), $stars_count );
 
                return sprintf(
                    '<blockquote %s>
                        <p class="testimonial__stars" aria-label="%s">%s</p>
                        <p class="testimonial__body">%s</p>
                        <cite class="testimonial__attribution">
                            <strong>%s</strong>%s
                        </cite>
                    </blockquote>',
                    // Merges your class with editor-added colour, spacing, and typography styles
                    get_block_wrapper_attributes( array( 'class' => 'testimonial wp-block-quote' ) ),
                    esc_attr( $stars_label ),
                    esc_html( $stars_html ),
                    wp_kses_post( $attributes['body'] ),
                    esc_html( $attributes['name'] ),
                    $attributes['company'] ? ', ' . esc_html( $attributes['company'] ) : ''
                );
            },
            'supports' => array(
                // The key flag — tells WordPress to handle JS registration automatically
                'autoRegister' => true, 
                // The rest unlock native colour, typography, and spacing panels in the sidebar
                'color'      => array(
                    'background' => true,
                    'text'       => true,
                ),
                'typography' => array(
                    'fontSize' => true,
                ),
                'spacing'    => array(
                    'padding' => true,
                    'margin'  => true,
                ),
            ),
        )
    );
}
add_action( 'init', 'my_plugin_register_testimonial_block' );

效果如下:

仅用 PHP 创建的 WordPress 自定义区块示例
带有自动生成控件和编辑器画布实时预览的纯 PHP 评价区块,与短代码版本的对比。

这里有几点值得注意。首先,短代码的内部内容在纯 PHP 区块中没有直接对应物。评论正文变成了一个从侧边栏检查器控件编辑的 string 属性——一个单行文本字段,而非画布内可编辑的富文本区域。对于简短的评价引文来说这没问题。对于较长的正文内容,您需要带有 RichText 组件的 JavaScript 注册区块。

其次,get_block_wrapper_attributes() 会将您的类与编辑器为颜色、字体排版和间距添加的内容合并——因此原生样式面板无需额外的 CSS 配置即可正常工作。render_callback 接收一个只包含用户设置值的 $attributes 数组;没有 $content 参数,因为不支持内部内容。

与短代码版本相比,您获得的优势:

  • 编辑器画布中的实时预览。 不再显示原始短代码语法——作者在编辑时即可看到渲染后的评价卡片。
  • 自动生成的控件。 姓名、公司、正文(文本输入)和星级(数字输入)自动出现在侧边栏检查器控件中。
  • 原生颜色、字体和间距面板。 来自 supports——无需自定义 CSS。
  • 易于发现。 区块以其名称和图标显示在插入器中。

开箱即用的翻译支持

使用纯 PHP 区块时,有两个不同的翻译问题,值得弄清楚各自是什么。

第一个是嵌入 PHP 模板中的静态字符串——标签、按钮文本、UI 文案。这些与任何 WordPress PHP 文件一样,通过 __()_e() 处理。在上面的区块中,星级标签就是一个例子:

/* translators: %d: star rating out of 5 */
$stars_label = sprintf( __( '%d out of 5 stars', 'my-plugin' ), $stars_count );

标准的 WordPress 工具会自动处理这些。无需额外配置。

第二个问题是存储为区块属性的用户输入内容——评价正文、评价者姓名、公司名称。这是编辑者实际在区块中输入的内容,__() 不会处理它。在多语言站点上,这些属性值需要单独翻译成每种语言,而这不是 WordPress 自身能处理的。

Gato AI Translations for Polylang 开箱即用地支持纯 PHP 区块,与支持 Gutenberg、Bricks、Elementor 和其他页面构建器的方式相同。无需额外设置。

所有 string 属性均自动注册以供翻译。如果某个特定字段不应被翻译——内部引用、URL、存储为字符串的数字代码——您可以使用过滤器将其排除。

对于本文中的评价区块,评价者姓名、公司和正文文本均会自动翻译——只需安装插件即可,无需任何配置。

纯 PHP 区块目前无法做的事情

纯 PHP 区块当前的限制:

  • 不支持内部区块或嵌套。 您无法在纯 PHP 区块内部放置其他区块。
  • 不支持画布内富文本编辑。 RichText 组件需要 JavaScript。文本控件仅作为侧边栏文本字段渲染。
  • 侧边栏字符串字段为单行。 string 属性变为 TextControl 而非 TextareaControl——不适合较长的文本内容。
  • 没有图片或媒体选择器属性。 图片/文件上传支持计划通过 Block Fields API 在后续版本中提供。
  • 编辑器预览存在往返延迟。 属性更改会触发 REST API 请求以在服务器上重新渲染,因此预览不会即时更新。

对于简单的结构化区块——评价、CTA、公告、作者简介、商家列表——纯 PHP 区块恰到好处。对于任何需要画布内富文本编辑的内容,JavaScript 注册仍然是正确的工具。

下一步

WordPress 7.0 的纯 PHP 区块让区块开发触手可及,适合所有 PHP 开发者。一个 PHP 文件,一次 register_block_type() 调用,您就拥有了一个功能完整的 Gutenberg 区块,具备侧边栏控件、实时画布预览和原生样式支持。您写 PHP,就能得到一个区块。无需工具。无需构建。无需 JavaScript。

如果您正在构建多语言站点,Gato AI Translations 与纯 PHP 区块无缝配合——您的内容从第一天起就可以翻译。

准备好更进一步了吗?


了解接下来会推出什么

订阅我们的新闻通讯:当我们发布新版本、推出新插件或有消息要分享时,第一时间通知你。