如何构建纯PHP的古腾堡区块

如何构建纯PHP的古腾堡区块

文章目录

  • 什么是纯PHP区块?它们为何如此重要?
  • 如何构建您的第一个纯PHP古腾堡区块
  • 使用属性构建区块设置UI
  • 纯PHP区块的实际应用示例
  • 使用纯PHP将旧版短代码转换为古腾堡区块
  • 纯PHP代码区块如何改变WordPress开发?

如何构建纯PHP的古腾堡区块

多年来,要精通 Gutenberg 区块开发,需要深入了解 React 和 Node.js 等技术,以及复杂的构建步骤和 JavaScript 工具。

然而,WordPress 开发正在不断发展,现在您可以完全使用 PHP 构建和管理 Gutenberg 区块。

这对于那些不想使用 React 和服务器端 JavaScript (JS) 开发的开发者来说尤其有利。它降低了学习难度,简化了开发体验,并通过消除不必要的前端脚本开销来提高性能。

在接下来的章节中,您将学习如何利用这些新特性来构建纯 PHP 的 Gutenberg 区块。在此过程中,您将学会创建更精简、更快速、更易于维护的 WordPress 网站。

警告:请注意,本文中仅包含 PHP 区块的部分目前处于实验阶段,可能会有所更改。请勿在生产环境中使用此功能!

什么是纯PHP区块?它们为何如此重要?

传统上,创建 Gutenberg 区块需要高级的服务器端 JavaScript 和 React 编码技能。这成为资深 WordPress 开发者采用区块编辑器的一大障碍,因为他们可能缺乏必要的 React 和 Node.js 知识。

现在情况正在改变。从 Gutenberg 21.8 开始,您可以使用纯 PHP 注册 Gutenberg 区块。这避免了为不熟悉服务器端 JavaScript 的用户搭建 Node.js 环境的复杂性。

通过纯 PHP 区块注册,您可以使用同一套 PHP 代码在编辑器和前端注册和显示区块。这鼓励使用混合主题或传统 PHP 函数和短代码的网站采用区块编辑器进行开发。

如果您想了解更多信息,请查看以下专门讨论纯 PHP 区块的主要 GitHub PR。

如何构建您的第一个纯PHP古腾堡区块

当一个区块仅在服务器端注册(不包含 JS 文件)且新的 auto_register 支持标志设置为 true 时,编辑器会自动使用 ServerSideRender 组件在客户端注册该区块并显示区块预览。本质上,区块的内容现在直接由编辑器和前端的 PHP 代码生成。

注:本文中的示例仅适用于已在开发网站上安装 Gutenberg 22.3 或更高版本的网站。

例如,以下是一个简单的 PHP 示例,它使用纯 PHP 方法注册一个区块。

/**
* Render callback (frontend and editor)
*/
function my_php_only_block_render( $attributes ) {
return '<div>
<h3>🚀 PHP-only Block</h3>
<p>This block was created with only PHP!</p>
</div>';
}
/**
* Register the block on the 'init' hook.
*/
add_action( 'init', function() {
register_block_type( 'my-plugin/php-only-test-block', array(
'title'           => 'My PHP-only Block',
'icon'            => 'welcome-learn-more',
'category'        => 'text',
'render_callback' => 'my_php_only_block_render',
'supports'        => array(
// Automatically registers the block in the Editor JS (previously auto_ssr)
'auto_register' => true, 
),
) );
});

您可以将此代码复制粘贴到自定义插件的主文件中进行测试。激活插件后,您应该会在区块插入器中看到“My PHP-Only Block”。

一个简单的纯 PHP 区块

一个简单的纯 PHP 区块

register_block_type  函数用于在服务器上注册区块类型。它现在支持新的 auto_register 属性,指示 Gutenberg 传递来自 PHP 注册的元数据。

该函数接受两个参数:

  • 区块类型的名称,包括命名空间。在本例中,区块名称为 my-plugin/php-only-test-block。
  • 区块类型的参数数组。在上面的代码中,我们设置了 title, icon, category, render_callback, 和 supports。同样,对于纯 PHP 区块类型,supports 数组必须包含 'auto_register' => true。

According to Héctor Priethor,

除了简化自定义区块类型的创建并使其易于集成到混合主题中之外,纯 PHP 区块还可以用作旧版 PHP 函数和短代码的封装。此外,使用纯 PHP 区块为自定义集成和服务器端功能开辟了新的可能性。

据 Héctor Priethor 所述:

纯 PHP 注册模型将简化区块开发的最低要求,使其适用于更广泛的开发者群体,并有助于区块生态系统超越高级 JavaScript 的使用。

使用属性构建区块设置UI

PR 74102 实现了从区块属性定义自动生成检查器控件。这使得用户可以像配置任何通过 JavaScript 注册的 Gutenberg 区块一样配置纯 PHP 区块的外观和功能。

以前,您必须手动在 React 中创建一个 edit.js 文件,并使用 React 组件定义各种设置控件。

现在,Gutenberg 会读取属性定义,并在 WordPress 编辑器中自动生成相应的输入字段。

系统会将 attributes 数组中定义的数据类型映射到 DataForm 字段定义。

  • 'type' => 'string' 生成一个文本字段。
  • 'type' => 'number' 生成一个数字字段。
  • 'type' => 'integer' 会生成一个整数字段。
  • 'type' => 'boolean' 会生成一个复选框。
  • 'type' => 'string' 并结合 'enum' => array() 会生成一个下拉选择框。

你会发现你只能使用少数几种控件。如果你需要特定的控件,例如 RichText, RangeControl, 或 ToggleControl,你仍然需要选择使用 JS/React 来实现。

然而,这种新增功能也带来了显著的优势。它进一步降低了入门门槛,你无需学习 React、Webpack 或 NPM 即可创建带有简单可编辑选项的自定义区块。

在下面的示例中,我们通过添加一些属性来扩展上一节中显示的示例区块。

/**
* 1. Define the block's HTML output.
*/
function my_php_only_block_render( $attributes ) {
// Extract attributes
$title   = esc_html( $attributes['blockTitle'] );
$count   = intval( $attributes['itemCount'] );
$enabled = $attributes['isEnabled']; // Boolean from the ToggleControl
$size    = esc_attr( $attributes['displaySize'] );
// Start building the output
$output = sprintf( '<div class="my-php-block" style="font-size: %s; border: 1px solid #ccc; padding: 15px;">', 
$size === 'large' ? '20px' : ($size === 'small' ? '12px' : '16px') 
);
$output .= sprintf( '<h3>🚀 %s</h3>', $title );
// If the toggle is ON, show the list. If OFF, show a fallback message.
if ( $enabled ) {
$output .= '<ul>';
for ( $i = 1; $i <= $count; $i++ ) {
$output .= sprintf( '<li>Item %d</li>', $i );
}
$output .= '</ul>';
} else {
$output .= '<p><em>The list is currently disabled.</em></p>';
}
$output .= '</div>';
return $output;
}
/**
* 2. Register the block on 'init'.
*/
add_action( 'init', function() {
register_block_type( 'my-plugin/php-only-test-block', array(
'title'           => 'My PHP-only Block',
'icon'            => 'welcome-learn-more',
'category'        => 'text',
'render_callback' => 'my_php_only_block_render',
// Attributes used to generate the Inspector UI
'attributes'      => array(
'blockTitle'  => array(
'type'    => 'string',
'default' => 'PHP-only Block',
),
'itemCount'   => array(
'type'    => 'integer',
'default' => 3,
),
'isEnabled'   => array(
'type'    => 'boolean',
'default' => true,
),
'displaySize' => array(
'type'    => 'string',
'enum'    => array( 'small', 'medium', 'large' ),
'default' => 'medium',
),
),
'supports'        => array(
'auto_register' => true, 
),
) );
});

快速浏览这段代码即可发现,使用新的 API 注册自定义区块及其所有配置设置是多么简单。属性现在不仅用于存储用户输入的数据,还用于定义 UI 架构。上面的代码执行以下操作:

  • register_block_type 函数注册区块类型 my-plugin/php-only-test-block。
  • 传递给该函数的第二个参数是一个数组,其中包含以下元素:title, icon, category, render_callback, attributes, 和 supports。
  • attributes 数组包含区块的属性。在上面的示例中,该数组包含元素 blockTitle, itemCount, isEnabled, 和 displaySize。
  • 'auto_register' => true 启用服务器端自动注册。

Here is what the callback function my_php_only_block_render does:

以下是回调函数 my_php_only_block_render 的工作原理:

  • 首先,该函数从 $attributes 数组中提取属性值,并将它们分别赋值给 $title, $count, $enabled, 和 $size 变量。
  • 然后,它生成区块的内容。

以下是屏幕上的显示结果:

一个纯 PHP 区块及其设置

一个纯 PHP 区块及其设置

纯PHP区块的实际应用示例

虽然在很多情况下仍然需要 JavaScript,但纯 PHP 区块已经可以实现很多功能,尤其是在使用区块属性时。

在下面的示例中,我们使用 get_block_wrapper_attributes() 函数,该函数会为当前渲染的区块生成一个属性字符串。区块会自动接收用户设置的颜色、边框和阴影,并将相应的样式应用到主容器。这样,就可以像使用 React 区块一样,通过 Gutenberg 的原生工具自定义区块。

要查看实际效果,请在您的计算机上创建一个名为 smart-pricing-widget 的文件夹。在该文件夹中,创建一个名为 style.css 的文件,并添加以下 CSS 代码:

/* style.css */
.pricing-card {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
box-sizing: border-box;
}
.pricing-card h3 {
margin: 0;
font-size: 1.5rem;
}
.pricing-card .price-value {
font-size: 3.5rem;
font-weight: 800;
margin: 15px 0;
}
.pricing-card ul {
list-style: none;
padding: 25px 0;
margin: 20px 0;
width: 100%;
border-top: 1px solid rgba(128,128,128,0.3);
display: flex;
flex-direction: column;
gap: 12px;
}
.pricing-card li {
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
}
.pricing-card .cta-button {
margin-top: auto;
padding: 15px 25px;
border-radius: 8px;
text-decoration: none;
font-weight: bold;
transition: opacity 0.2s;
}
.pricing-card .cta-button:hover {
opacity: 0.8;
}
/* Theme Variations */
.pricing-card.theme-light { background-color: #ffffff; color: #000000; }
.pricing-card.theme-light .cta-button { background-color: #21759b; color: #ffffff; }
.pricing-card.theme-dark { background-color: #1a1a1a; color: #ffffff; }
.pricing-card.theme-dark .cta-button { background-color: #ffffff; color: #1a1a1a; }
.pricing-card.theme-blue { background-color: #21759b; color: #ffffff; }
.pricing-card.theme-blue .cta-button { background-color: #000000; color: #ffffff; }
/* Utility Classes */
.pricing-card .is-full-width {
width: 100%;
display: block;
align-self: stretch;
}

由于这只是一个简单的组件区块样式表,我们不会对此代码进行任何注释。

现在,创建插件的主文件,将其命名为 smart-pricing-widget.php,并将以下代码粘贴到该文件中:

<?php
/**
* Plugin Name: Smart Pricing Widget
* Plugin URI:  https://example.com/
* Description: PHP-only Pricing Table block
* Version:     1.2.0
* Author:      Your Name
* Text Domain: smart-pricing-widget
*/
if ( ! defined( 'ABSPATH' ) ) exit;
/**
* Render callback
*/
function render_smart_pricing_block( $attributes ) {
$plan_name = esc_html( $attributes['planName'] );
$price     = intval( $attributes['price'] );
$theme     = $attributes['blockTheme'];
$btn_text  = esc_html( $attributes['buttonText'] );
$btn_size  = $attributes['buttonSize'];
$features_raw = $attributes['featuresList'];
$features_array = array_filter( array_map( 'trim', explode( ',', $features_raw ) ) );
$wrapper_attributes = wp_kses_data( get_block_wrapper_attributes( array(
'class' => "pricing-card theme-{$theme}",
) ) );
$output = sprintf( '<div %s>', $wrapper_attributes );
$output .= sprintf( '<h3>%s</h3>', $plan_name );
$output .= sprintf( '<div class="price-value">€%d</div>', $price );
if ( ! empty( $features_array ) ) {
$output .= '<ul>';
foreach ( $features_array as $feature ) {
$is_checked = strpos( $feature, '+' ) === 0;
$clean_text = esc_html( ltrim( $feature, '+- ' ) );
$icon       = $is_checked ? '✅' : '❌';
$style      = $is_checked ? '' : 'style="opacity: 0.6;"';
$output .= sprintf( '<li %s><span>%s</span> %s</li>', $style, $icon, $clean_text );
}
$output .= '</ul>';
}
$btn_class = 'cta-button' . ( $btn_size === 'full' ? ' is-full-width' : '' );
$output .= sprintf( '<a href="#" class="%s">%s</a>', esc_attr( $btn_class ), $btn_text );
$output .= '</div>';
return $output;
}
/**
* Register Assets and Block
*/
add_action( 'init', function() {
// 1. Register the CSS file
wp_register_style(
'smart-pricing-style',
plugins_url( 'style.css', __FILE__ ),
array(),
'1.2.0'
);
// 2. Register the Block
register_block_type( 'tutorial/smart-pricing', array(
'api_version'     => 3,
'title'           => 'Pricing Card',
'icon'            => 'cart',
'category'        => 'widgets',
'render_callback' => 'render_smart_pricing_block',
// Link the registered style handle here
'style'           => 'smart-pricing-style',
'attributes'      => array(
'planName'     => array( 'type' => 'string', 'default' => 'Professional' ),
'price'        => array( 'type' => 'integer', 'default' => 49 ),
'buttonText'   => array( 'type' => 'string', 'default' => 'Choose Plan' ),
'buttonSize'   => array( 'type' => 'string', 'enum' => array( 'auto', 'full' ), 'default' => 'auto' ),
'blockTheme'   => array( 'type' => 'string', 'enum' => array( 'light', 'dark', 'blue' ), 'default' => 'light' ),
'featuresList' => array( 'type' => 'string', 'default' => "+ Support, + Updates, - Domain" ),
),
'supports'        => array(
'auto_register' => true,
'color'         => array( 'background' => true, 'text' => true ),
'spacing'       => array( 'margin' => true, 'padding' => true ),
'typography'    => array( 'fontSize' => true ),
'shadow'        => true,
'__experimentalBorder' => array( 'color' => true, 'radius' => true, 'style' => true, 'width' => true ),
'border'        => array( 'color' => true, 'radius' => true, 'style' => true, 'width' => true ),
),
) );
});

此脚本包含两个函数。register_block_type() 函数是插件的核心。以下是其主要组成部分:

  • 第一个参数是区块标识符,包含命名空间( tutorial/smart-pricing )。
  • 第二个参数是一个参数数组。在上面的代码中,我们设置了 API 版本、标题、图标、类别、渲染回调、样式、属性和支持。
  • 数组中的属性生成用户用于添加内容和配置区块的控件。type 元素指定要添加到区块检查器的控件类型。在本例中,这些控件包括文本字段( 'type' => 'string' )、整数( 'type' => 'integer' )和几个下拉菜单( 'type' => 'string' ,'enum' => 'array()' )。
  • supports 数组项添加了使区块样式可自定义的功能。如前所述,纯 PHP 区块唯一需要的支持是 auto_register,它能为自定义属性自动生成 UI。其他支持包括颜色、间距、字体、阴影和边框。

回调函数 render_smart_pricing_block() 会生成区块的 HTML 代码。以下是该函数的详细说明:

  • 它会提取并清理区块属性,然后添加 CSS 代码,从而在前端和编辑器中生成区块的外观。
  • 区块中要显示的功能列表($attributes['featuresList'];)是单独处理的。目前,无法在区块设置侧边栏添加高级控件。要创建列表(例如功能列表),您只能使用简单的文本字段。在本例中,您必须手动输入产品功能,并用逗号分隔。
  • $wrapper_attributes 变量用于存储 get_block_wrapper_attributes 函数提供的包装器属性。该函数不仅会添加代码中指定的类(pricing-card theme-{$theme}),还会自动检索用户在区块检查器中设置的所有样式自定义项,包括颜色、边框、内边距、外边距、阴影、字体以及标准区块类(wp-block-tutorial-smart-pricing)。
  • wp_kses_data 确保字符串中不包含恶意标签或脚本(XSS)。
  • 其余代码生成区块内容。

激活插件并创建一个新文章或页面。打开区块插入器并向下滚动到“小工具”部分。在这里,您应该可以看到带有购物车图标的“Pricing Card”区块。

自定义的纯 PHP 区块

自定义的纯 PHP 区块(位于区块编辑器中)

上图显示的是默认浅色主题下的区块。

下图显示的是深色主题下的区块,以及您在插件中设置的属性。

仅支持 PHP 的区块及其设置

仅支持 PHP 的区块及其设置

下图展示了您使用区块支持添加的样式控件。

仅使用 PHP 编写的区块的深色主题

仅使用 PHP 编写的区块的深色主题,支持自定义颜色

值得注意的是,支持人员添加的样式会覆盖区块主题样式。这使得区块外观可以进行更精细的自定义,如下图所示:

价格表

包含三个服务级别的价格表,每个级别对应三个 PHP 编写的区块实例

使用纯PHP将旧版短代码转换为古腾堡区块

PHP 区块最直接的用途之一是作为短代码封装器。在 Gutenberg 中,您仍然可以在内容中使用短代码,但必须手动将短代码插入到短代码区块中,这并非最佳体验。

假设您有以下短代码:

function my_custom_alert_shortcode( $atts ) {
$options = shortcode_atts( array(
'type'    => 'info',
'message' => 'Default alert message',
), $atts );
$styles = array(
'info'    => 'background: #d1ecf1; color: #0c5460; border-color: #bee5eb;',
'warning' => 'background: #fff3cd; color: #856404; border-color: #ffeeba;',
'error'   => 'background: #f8d7da; color: #721c24; border-color: #f5c6cb;'
);
$style = $styles[ $options['type'] ] ?? $styles['info'];
return sprintf(
'<div class="sc-alert-box" style="%s padding: 20px; border: 1px solid; border-radius: 6px; margin: 10px 0;">
<strong style="text-transform: uppercase;">%s:</strong> %s
</div>',
esc_attr( $style ),
esc_html( $options['type'] ),
esc_html( $options['message'] )
);
}
add_shortcode( 'sc_alert', 'my_custom_alert_shortcode' );

这段代码会生成一个简单的框,您可以使用以下短代码将其插入到您的内容中:

[sc_alert type="alert" message="Hello"]

在 Gutenberg 编辑器中,您可以使用简码区块将框插入到您的内容中,如下图所示:

短代码区块

短代码区块

使用纯 PHP 区块后,情况就完全不同了。现在,您可以将短代码封装在纯 PHP 古腾堡区块中,并通过 UI 控件进行配置。以下是需要添加到插件中的代码:

/**
* Rendering callback
*/
function render_shortcode_alert_wrapper_block( $attributes ) {
$type    = esc_attr( $attributes['alertType'] );
$message = esc_attr( $attributes['alertMessage'] );
$shortcode_string = sprintf( '[sc_alert type="%s" message="%s"]', $type, $message );
$wrapper_attributes = wp_kses_data( get_block_wrapper_attributes( array(
'class' => 'wp-block-shortcode-alert-wrapper',
) ) );
return sprintf(
'<div %s>%s</div>',
$wrapper_attributes,
do_shortcode( $shortcode_string )
);
}
/**
* Register the block type on the server
*/
add_action( 'init', function() {
register_block_type( 'tutorial/alert-wrapper', array(
'api_version'     => 3,
'title'           => 'Alert (Shortcode wrapper)',
'icon'            => 'feedback',
'category'        => 'widgets',
'render_callback' => 'render_shortcode_alert_wrapper_block',
'attributes'      => array(
'alertType' => array(
'type'    => 'string',
'enum'    => array( 'info', 'warning', 'error' ),
'default' => 'info',
),
'alertMessage' => array(
'type'    => 'string',
'default' => 'Type your alert message here...',
),
),
'supports'        => array(
'auto_register' => true,
'spacing'       => array( 'margin' => true, 'padding' => true ),
'typography'    => array( 'fontSize' => true ),
),
) );
});

上面的代码与上一节中的代码类似。不同之处在于渲染回调函数。

  • $shortcode_string 存储短代码字符串(例如 [sc_alert type="%s" message="%s"])。
  • 该函数返回包含短代码的区块容器的 HTML 代码(do_shortcode( $shortcode_string ))。

现在,打开区块插入器,在组件中找到“Shortcode wrapper”区块。将其插入到您的内容中,并在区块设置栏中进行配置。该区块在编辑器和前端的显示效果将完全相同。

用纯 PHP 区块封装的短代码示例

一个用纯 PHP 区块封装的短代码示例

纯PHP代码区块如何改变WordPress开发?

目前,纯 PHP 区块仍处于实验阶段,功能有限。Gutenberg 提供了更强大的功能,例如区块样板和区块变体,它们提供了原生 Gutenberg 区块和用 JavaScript 构建的自定义区块的所有编辑功能。然而,在某些情况下,纯 PHP 区块也提供了重要的机遇。

首先,纯 PHP 区块应该能够促进区块编辑器的更广泛应用,尤其是在那些不太熟悉服务器端 JavaScript 开发的 WordPress 开发者中。

此外,它们是自定义函数和短代码的理想封装,正如本文示例所示。而且,它们还允许轻松地与外部服务集成。

我们还可以合理地期待未来的改进和功能添加,更多的配置控制以及与现有 Gutenberg 工具的集成。

有一点可以肯定:有了纯 PHP 区块,构建 Gutenberg 区块变得更加容易。

评论留言