社区新闻

如何为插件页面使用 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>
   );
};

PanelPanelBodyPanelRow 组件总是结合使用。这些以及后续组件提供了各种选项,并非所有选项都是本项目所必需的。你可以通过探索 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 属性禁用此可能性。

最后一次,用实际组件替换占位符文本,并配置 valueonChange 属性:

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>