如何为插件页面使用 WordPress React 组件
如果你曾觉得大多数 WordPress 管理区域相比现代、动态的文章和站点编辑器显得静态而过时,你并非孤身一人。
但好消息是:这种情况正在改变。随着 WordPress 进入第三阶段:协作,正在持续努力改进整体管理体验,并将新的视觉语言整合到各处。
WordPress 生态系统也在变化。许多知名插件已经更新了它们的设置页面。越来越多的开发者选择使用 React 来构建用户界面,以提升用户体验并加快新功能的引入速度。
如果你想做同样的事情呢?
本文将指导你利用 WordPress React 组件为插件创建一个基于 React 的设置页面。
你将构建什么?
在本文中,你将构建一个插件,它会在前端页眉上方显示一个公告栏。
它将包含一个设置页面,允许你自定义消息、切换公告栏的可见性以及调整其大小。
模块化架构的力量
与文章和站点编辑器交互会给人一种统一系统的印象。然而,它们是独立组件和包协调工作的产物。
从一开始,Gutenberg 项目就采用了松耦合或完全解耦的包。借助这种模块化架构,可以创建不同的界面甚至应用程序。
你将使用这些包来创建一个设置页面,但考虑到它们的可重用性和多功能性,你甚至可以将它们用于非 WordPress 项目。
假设知识与先决条件
本文假设你对 React 有一定了解。如果你曾经开发过基本的自定义块,那么本文会特别容易上手,因为相关技能和概念高度可迁移。
如果你想跟着编码,请创建以下起始文件:
/plugins/unadorned-announcement-bar/
├── index.php
├── package.json
└── src/
├── index.js
└── index.scss
你还需要 wp-scripts 用于 JavaScript 构建步骤。关于设置和使用它的逐步指南,请查看开始使用 wp-scripts。
如果你已经熟悉它,以下是 package.json 中需要的内容:
{
"devDependencies": {
"@wordpress/scripts": "^27.0.0"
},
"scripts": {
"build": "wp-scripts build",
"start": "wp-scripts start"
}
}
奠定基础
最初的步骤与创建具有“传统”自定义设置页面的插件并无不同。
如果你需要更多关于任何步骤的信息,可以参考插件基础页面。
设置菜单和设置页面
首先,在 index.php 文件中添加最低要求的插件头部注释,然后在设置菜单下注册一个子菜单:
<?php
/**
* Plugin Name: Unadorned Announcement Bar
*/
function unadorned_announcement_bar_settings_page() {
add_options_page(
__( 'Unadorned Announcement Bar', 'unadorned-announcement-bar' ),
__( 'Unadorned Announcement Bar', 'unadorned-announcement-bar' ),
'manage_options',
'unadorned-announcement-bar',
'unadorned_announcement_bar_settings_page_html'
);
}
add_action( 'admin_menu', 'unadorned_announcement_bar_settings_page' );
接下来,将回调函数添加到同一个 PHP 文件:
function unadorned_announcement_bar_settings_page_html() {
printf(
'<div class="wrap" id="unadorned-announcement-bar-settings">%s</div>',
esc_html__( 'Loading…', 'unadorned-announcement-bar' )
);
}
只需输出一个具有唯一 id 的 HTML 元素即可。你将使用这个 id 在 JavaScript 中定位该元素。“Loading…”消息将在 JavaScript 部分初始化后被替换。
要访问你的设置页面,请转到设置,然后选择Unadorned Announcement Bar。

为 React 加载 JavaScript
由于你正在构建一个基于 React 的设置页面,必须加载必要的 JavaScript 文件。为此,将以下代码添加到 index.php 文件:
function unadorned_announcement_bar_settings_page_enqueue_style_script( $admin_page ) {
if ( 'settings_page_unadorned-announcement-bar' !== $admin_page ) {
return;
}
$asset_file = plugin_dir_path( __FILE__ ) . 'build/index.asset.php';
if ( ! file_exists( $asset_file ) ) {
return;
}
$asset = include $asset_file;
wp_enqueue_script(
'unadorned-announcement-bar-script',
plugins_url( 'build/index.js', __FILE__ ),
$asset['dependencies'],
$asset['version'],
array(
'in_footer' => true,
)
);
}
add_action( 'admin_enqueue_scripts', 'unadorned_announcement_bar_settings_page_enqueue_style_script' );
你遵循了最佳实践,确保 JavaScript 仅在设置页面加载,并且由于你动态设置了依赖项和版本,因此永远不需要更新它们。
构建文件夹及其内容是在使用 wp-scripts 编译 JavaScript 时创建的。
启动 React 设置页面
完成前面的步骤后,终于可以编写一些 React 代码了。
为了确认一切正常,可以从一些基础内容开始,比如渲染一个占位符组件。
将此代码添加到你的 src/index.js 文件:
import domReady from '@wordpress/dom-ready';
import { createRoot } from '@wordpress/element';
const SettingsPage = () => {
return <div>Placeholder for settings page</div>;
};
domReady( () => {
const root = createRoot(
document.getElementById( 'unadorned-announcement-bar-settings' )
);
root.render( <SettingsPage /> );
} );
记得使用 npm install {package} 安装提到的包。当你遇到对新包的引用时,也请安装它们。如果还没有,请启动 wp-scripts 构建过程。
通过使用 domReady,你可以确保 DOM 已准备好进行操作。在回调内部,使用 createRoot 告诉 React 接管指定元素的 DOM 管理。然后,就是渲染 SettingsPage 组件的问题了。
这些步骤是所有 React 应用程序共有的。文章和站点编辑器初始化时也会发生非常类似的事情。
如果你刷新设置页面,应该会看到显示的占位符消息:

适用于 WordPress 及其他地方的可重用 UI 元素
@wordpress/components 是核心包之一。它经常被使用,因为它包含了用于块编辑器和站点编辑器的常见 UI 元素,但它们足够通用,可以在其他地方使用。
请参阅 WordPress Storybook 以获取可用组件的概述。Storybook 允许你单独浏览各个组件、它们的控件、选项和设置。你可以修改它们的控件和参数,并立即看到变化。

有各种各样的组件可用,随着 WordPress 更多区域进行改造,这个列表有望继续扩展。
在 Storybook 中,你与 React 代码组件 交互,这些组件也作为视觉组件存在。它们与代码中可用和实现的内容完全一致。
视觉组件
视觉组件是可重用的 UI 片段,可用于 Figma 来创建模型,并在编写任何代码之前尽早探索想法。
你只需从可用的视觉组件中选择,就可以为插件创建一个模型:

如果你想与 WordPress 的设计保持一致,只需组合和排列几个控件,再加上一个按钮和一个标题:

构建设置页面的 UI
面板
根据模型,你的设置被分为两个部分,其中外观部分默认是隐藏的。
Panel 组件非常适合这个用例,因为它创建了一个带有可选标题的容器,并接受一个可以折叠的 PanelBody 组件。
要集成它,首先需要在 src/index.js 文件的顶部导入依赖项:
import { __ } from '@wordpress/i18n';
import { Panel, PanelBody, PanelRow } from '@wordpress/components';
请记住,import 语句始终放在文件顶部。为了避免重复,从现在开始不会明确提及这个细节。
然后,修改你的 SettingsPage 组件。目前,在控件最终放置的位置使用占位符消息:
const SettingsPage = () => {
return (
<Panel>
<PanelBody>
<PanelRow>
<div>Placeholder for message control</div>
</PanelRow>
<PanelRow>
<div>Placeholder for display control</div>
</PanelRow>
</PanelBody>
<PanelBody
title={ __( 'Appearance', 'unadorned-announcement-bar' ) }
initialOpen={ false }
>
<PanelRow>
<div>Placeholder for size control</div>
</PanelRow>
</PanelBody>
</Panel>
);
};
Panel、PanelBody 和 PanelRow 组件总是结合使用。这些以及后续组件提供了各种选项,并非所有选项都是本项目所必需的。你可以通过探索 Storybook 来发现更多可能性。
此时,如果你刷新设置页面,应该会看到渲染的组件:

包含组件的样式
目前,看起来不太对劲。这是因为默认情况下组件是无样式的,你仍然需要包含它们的 CSS。
你可以通过加载 wp-components 样式表来解决这个问题。修改 index.php 文件中的当前函数:
function unadorned_announcement_bar_settings_page_enqueue_style_script( $admin_page ) {
// ...
wp_enqueue_style( 'wp-components' );
}
现在,你的设置页面应该看起来像 WordPress 风格了:

管理控件的状态
对于这个插件,你不需要任何复杂的状态管理。只有三个控件和三个值需要跟踪,你可以从三个 useState 实例和一些默认值开始。
最好将其封装在一个自定义 Hook 中,以将状态与表示层分离。从这里开始,除非另有说明,将所有代码添加到 src/index.js 文件:
import { useState } from '@wordpress/element';
const useSettings = () => {
const [ message, setMessage ] = useState('Hello, World!');
const [ display, setDisplay ] = useState(true);
const [ size, setSize ] = useState('medium');
return {
message,
setMessage,
display,
setDisplay,
size,
setSize,
};
};
虽然你的代码目前只有几行,但一旦你尝试从数据库保存或加载数据,复杂性将不可避免地增加。自定义 Hook 和拥有状态管理中心的好处很快就会变得更加明显。请继续关注。
要在 SettingsPage 组件中访问状态变量和设置函数,请调用 useSettings 并解构返回的对象:
const SettingsPage = () => {
const {
message,
setMessage,
display,
setDisplay,
size,
setSize,
} = useSettings();
// ...
};
消息控件
为了允许公告栏消息有更长的文本,使用 TextareaControl 组件是不会错的。
为了保持整洁,将其包装在一个单独的组件中:
import { TextareaControl } from '@wordpress/components';
const MessageControl = ( { value, onChange } ) => {
return (
<TextareaControl
label={ __( 'Message', 'unadorned-announcement-bar' ) }
value={ value }
onChange={ onChange }
__nextHasNoMarginBottom
/>
);
};
随着 WordPress 的发展,有时需要调整现有组件的样式。当引入新样式时,它们会放在以 __next 为前缀的特性标志属性后面。这为第三方提供了一个宽限期来进行必要的调整。
创建它之后,下一步是用 MessageControl 组件替换占位符。使用 message 常量作为值,并在你的 onChange 处理程序中使用其设置函数:
const SettingsPage = () => {
const {
message,
setMessage,
// ...
} = useSettings();
return (
<Panel>
<PanelBody>
<PanelRow>
<MessageControl
value={ message }
onChange={ ( value ) => setMessage( value ) }
/>
</PanelRow>
<PanelRow></PanelRow>
</PanelBody>
<PanelBody></PanelBody>
</Panel>
);
};
完成所有这些工作后,你的第一个控件就可以工作了,允许你更新消息:

显示控件
要切换公告栏的可见性,你需要一个开/关开关。选择 ToggleControl 组件。
为了保持一致性,请遵循与上一节相同的方法。首先,为控件创建一个单独的组件:
import { ToggleControl } from '@wordpress/components';
const DisplayControl = ( { value, onChange } ) => {
return (
<ToggleControl
label={ __( 'Display', 'unadorned-announcement-bar' ) }
checked={ value }
onChange={ onChange }
__nextHasNoMarginBottom
/>
);
};
然后,用 DisplayControl 组件替换你已有的占位符,并为 onChange 处理程序使用相应的常量和设置函数:
const SettingsPage = () => {
const {
// ...
display,
setDisplay,
// ...
} = useSettings();
return (
<Panel>
<PanelBody>
<PanelRow></PanelRow>
<PanelRow>
<DisplayControl
value={ display }
onChange={ ( value ) => setDisplay( value ) }
/>
</PanelRow>
</PanelBody>
<PanelBody></PanelBody>
</Panel>
);
};
尺寸控件
对于尺寸控件,你有几个不同的组件可以选择,但最合适的是多功能的 FontSizePicker 组件。
与之前的控件类似,为其创建一个单独的组件。唯一的区别是你必须定义可能的选项列表:
import { FontSizePicker } from '@wordpress/components';
const SizeControl = ( { value, onChange } ) => {
return (
<FontSizePicker
fontSizes={ [
{
name: __( 'Small', 'unadorned-announcement-bar' ),
size: 'small',
slug: 'small',
},
{
name: __( 'Medium', 'unadorned-announcement-bar' ),
size: 'medium',
slug: 'medium',
},
{
name: __( 'Large', 'unadorned-announcement-bar' ),
size: 'large',
slug: 'large',
},
{
name: __( 'Extra Large', 'unadorned-announcement-bar' ),
size: 'x-large',
slug: 'x-large',
},
] }
value={ value }
onChange={ onChange }
disableCustomFontSizes={ true }
__nextHasNoMarginBottom
/>
);
};
默认情况下,你可以选择预定义值列表之外的任何尺寸,但为了保持“朴素”,使用 disableCustomFontSizes 属性禁用此可能性。
最后一次,用实际组件替换占位符文本,并配置 value 和 onChange 属性:
const SettingsPage = () => {
const {
// ...
size,
setSize,
} = useSettings();
return (
<Panel>
<PanelBody></PanelBody>
<PanelBody
title={ __( 'Appearance', 'unadorned-announcement-bar' ) }
initialOpen={ false }
>
<PanelRow>
<SizeControl
value={ size }
onChange={ ( value ) => setSize( value ) }
/>
</PanelRow>
</PanelBody>
</Panel>
);
};
此时,你的所有三个控件都已正常工作,这完成了工作的一半。你的设置页面现在应该看起来像这样:

保存按钮
要完成设置页面的基础部分,你还需要添加两个组件。
首先,你需要用于保存的 Button 组件。像之前一样,为其创建一个包装组件:
import { Button } from '@wordpress/components';
const SaveButton = ( { onClick } ) => {
return (
<Button variant="primary" onClick={ onClick } __next40pxDefaultSize>
{ __( 'Save', 'unadorned-announcement-bar' ) }
</Button>
);
};
接下来,在 Panel 组件之后立即添加 SaveButton 组件:
const SettingsPage = () => {
// ...
return (
<>
<Panel></Panel>
<SaveButton onClick={ () => {} } />
</>
);
};
点击时,它暂时不执行任何特定操作也没关系。你稍后会添加保存功能。
别忘了将两个组件包装在一个片段中(在 <></> 之间),因为在 React 中只能返回一个组件。
实验性标题
你可能已经在 Storybook 中注意到,有些组件被标记为实验性。
它们被称为实验性是因为 WordPress 的向后兼容性保证不适用于它们。它们可能从一个版本变化到另一个版本,可能会破坏代码。
请谨慎使用它们,但为了尝试它们,你可以使用 __experimentalHeading 组件作为标题,而不是普通的 h1 标签:
import {
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalHeading as Heading,
} from '@wordpress/components';
const SettingsTitle = () => {
return (
<Heading level={ 1 }>
{ __( 'Unadorned Announcement Bar', 'unadorned-announcement-bar' ) }
</Heading>