社区新闻

WordPress管理界面重新设计预览

WordPress正处于管理界面重新设计的过程中。在这个过渡阶段,管理界面由两部分组成:已存在十多年的“经典”界面,以及随区块和站点编辑器而来的“现代”界面。

如果你正在构建一个需要设置页面的插件,并且希望与WordPress核心用户体验保持一致,那么现在就开始采用将成为新标准的设计元素和模式是值得的。

一种方法是在构建设置页面时使用WordPress React组件。《如何为插件页面使用WordPress React组件》一文介绍了这种方法。然而,得益于过去一年左右许多人的工作,现在有一个值得考虑和探索的可行替代方案。

在本文中,你将学习如何重建之前使用独立React组件构建的相同设置页面,但这次使用DataFormDataForm组件提供了一种声明式创建表单和面板的方法,无需导入单独的组件。

作为预览,以下是设置页面当前的外观:

重构前

以下是重构完成后的最终结果:

重构后

前提条件

本文假设你已经阅读过《如何为插件页面使用WordPress React组件》并熟悉其中构建的内容。如果还没有,现在是个好时机!

本文不涉及如何注册管理页面、加载资源或通过REST API注册和公开设置。所有这些都在前一篇文章中介绍过,并且保持不变。

如果你想跟着操作,可以下载或克隆Unadorned Announcement Bar插件的仓库作为起点,并按照设置说明操作。本文的工作从前一篇文章结束的地方继续。

如果你在任何地方卡住了,可以将你的更改与dataform-refactor分支进行比较。每个步骤都单独提交了

原始的SettingsPage组件

“原始”的设置页面组件由多个组件和一个用于管理状态的自定义Hook组成。

SettingsPage组件的代码如下所示:

const SettingsPage = () => {
    const {
        message,
        setMessage,
        display,
        setDisplay,
        size,
        setSize,
        saveSettings,
    } = useSettings();

    return (
        <>
            <SettingsTitle />
            <Notices />
            <Panel>
                <PanelBody>
                    <PanelRow>
                        <MessageControl
                            value={ message }
                            onChange={ ( value ) => setMessage( value ) }
                        />
                    </PanelRow>
                    <PanelRow>
                        <DisplayControl
                            value={ display }
                            onChange={ ( value ) => setDisplay( value ) }
                        />
                    </PanelRow>
                </PanelBody>
                <PanelBody
                    title={ __( 'Appearance', 'unadorned-announcement-bar' ) }
                    initialOpen={ false }
                >
                    <PanelRow>
                        <SizeControl
                            value={ size }
                            onChange={ ( value ) => setSize( value ) }
                        />
                    </PanelRow>
                </PanelBody>
            </Panel>
            <SaveButton onClick={ saveSettings } />
        </>
    );
};

所有内容都是使用@wordpress/components包中的组件构建的。即使是像MessageControl这样的自定义组件,也仅仅是WordPress提供的组件的包装器:

const MessageControl = ( { value, onChange } ) => {
    return (
        <TextareaControl
            label={ __( 'Message', 'unadorned-announcement-bar' ) }
            value={ value }
            onChange={ onChange }
            __nextHasNoMarginBottom
        />
    );
};

使用DataForm时,不需要这些单独的组件,只需要DataForm本身。

安装@wordpress/dataviews

第一步,安装@wordpress/dataviews包,因为DataForm组件是其中的一部分。

在插件文件夹内运行以下命令:

npm install @wordpress/dataviews --save

接下来,通过在你的/src/components/settings-page.jsx文件开头添加以下内容来导入DataForm

import { DataForm } from '@wordpress/dataviews/wp';

目前,在WordPress环境中使用@wordpress/dataviews(与独立应用相对)时,必须从@wordpress/dataviews/wp导入,以确保依赖项正确解析

添加DataForm组件

由于你的settings-page.jsx文件中不再需要大多数独立组件,你可以将整个Panel组件及其子组件替换为DataForm组件:

const SettingsPage = () => {
    const {
        // ...    
    } = useSettings();

    return (
        <>
            <SettingsTitle />
            <Notices />
            <DataForm />
            <SaveButton onClick={ saveSettings } />
        </>
    );
};

DataForm需要一些属性(datafieldsformonChange),但现在你可以提供空值来开始。你马上就会看到它们的用途。

更改后,settings-page.jsx应该如下所示:

const SettingsPage = () => {
    const {
        // ...
    } = useSettings();

    const data = {};
    const fields = [];
    const form = {};

    return (
        <>
            <SettingsTitle />
            <Notices />
            <DataForm
                data={ data }
                fields={ fields }
                form={ form }
                onChange={ () => {} }
            />
            <SaveButton onClick={ saveSettings } />
        </>
    );
};

虽然你可以将属性值内联,但使用变量会使代码更易读,因为这些值将有多行长。

如果你刷新设置页面,应该只看到标题和保存按钮,就像从一张白纸开始一样。

第一步空白状态

配置表单字段

DataForm是配置驱动的。要定义一个字段,你至少需要提供一个id、一个label和一个type

id是字段的唯一标识符,可以是任何字符串。label是UI中显示的字段名称。

type定义了字段持有的数据类型,包括textintegerbooleandatetime等。有关完整列表,请查看文档,因为列表会随着包的演进而增长。

添加消息字段

对于消息字段,使用text类型,因为它需要是一个自由格式的文本字段。

要添加配置,请更新settings-page.jsx中的fields变量,该变量将保存所有字段的配置:

const SettingsPage = () => {
    // ...
    
    const data = {};
    const fields = [
        {
            id: 'message',
            label: __( 'Message', 'unadorned-announcement-bar' ),
            type: 'text',
        },
    ];
    const form = {};

    // ..
};

这定义了字段但并未渲染它。要实际显示消息字段,需要在form变量中包含字段的id

const SettingsPage = () => {
    // ...
    
    const data = {};
    const fields = [
        {
            id: 'message',
            // ...
        }
    ];
    const form = {
        fields: [ 'message' ], 
    };

    // ..
};

最后,你必须通过更新data变量来定义一个初始值。现在,将message字段设置为空字符串。

更新后的settings-page.jsx代码应如下所示:

const SettingsPage = () => {
    // ...
    
    const data = {
        message: '',
    };
    const fields = [
        {
            id: 'message',
            // ...
        }
    ];
    const form = {
        fields: [ 'message' ],
    };

    // ..
};

此时,如果你刷新插件的设置页面,应该会看到一个文本输入框被渲染出来。

截图:添加消息字段的结果

虽然它不像之前那样是文本区域,但你很快就会看到如何改变这一点。

添加显示字段

你可以对显示字段采用相同的方法。这次使用boolean类型而不是text类型,因为它代表开/关状态。

按如下方式更新settings-page.jsx中的变量:

const SettingsPage = () => {
    // ...
    
    const data = {
        message: '',
        display: false,
    };
    const fields = [
        {
            id: 'message',
            // ...
        },
        {
            id: 'display',
            label: __( 'Display', 'unadorned-announcement-bar' ),
            type: 'boolean',
        },
    ];
    const form = {
        fields: [ 'message', 'display' ],
    };

    // ..
};

在浏览器中刷新设置页面后,你应该会看到消息字段下方渲染了一个复选框字段。

添加显示字段的结果

添加字体大小字段

剩下的字段是字体大小。这应该允许用户从预定义的选项(如小、中等和其他)中进行选择。

DataForm中没有专门的“选择”类型。相反,使用text类型(因为值以字符串形式存储),并添加可选的elements属性来定义选项。当存在elements时,DataForm会渲染一个选择输入而不是文本输入。

更新后,settings-page.jsx应如下所示:

const SettingsPage = () => {
    // ...
    
    const data = {
        message: '',
        display: false,
        size: 'small',
    };
    const fields = [
        {
            id: 'message',
            // ...
        },
        {
            id: 'display',
            // ...
        },
        {
            id: 'size',
            label: __( 'Font size', 'unadorned-announcement-bar' ),
            type: 'text',
            elements: [
                {
                    value: 'small',
                    label: __( 'Small', 'unadorned-announcement-bar' ),
                },
                {
                    value: 'medium',
                    label: __( 'Medium', 'unadorned-announcement-bar' ),
                },
                {
                    value: 'large',
                    label: __( 'Large', 'unadorned-announcement-bar' ),
                },
                {
                    value: 'x-large',
                    label: __( 'Extra Large', 'unadorned-announcement-bar' ),
                },
            ]
        }
    ];
    const form = {
        fields: [ 'message', 'display', 'size' ],
    };

    // ..
};

这样,你的设置页面应该有三个字段,无需导入任何特定组件,全部通过配置对象定义。

截图:添加字体大小字段

自定义字段UI组件

当你为字段指定type而没有额外配置时,每种类型都会映射到一个默认的UI组件。

正如你所看到的,当未定义元素时,text类型会渲染一个文本输入。boolean会渲染一个复选框。

但是,你可以通过指定Edit属性来更改默认的UI组件。最简单的选项是使用预定义的UI组件之一:textareatoggleradiotoggleGroup等。

要完成此操作,请按如下方式将Edit属性添加到settings-page.jsx中的字段:

const SettingsPage = () => {
    // ...
    const fields = [
        {
            id: 'message',
            // ...
            Edit: 'textarea',
        },
        {
            id: 'display',
            // ...
            Edit: 'toggle',
        },
        {
            id: 'size',
            // ...
            Edit: 'toggleGroup',
        },
    ];
    // ..
};

现在,如果你刷新设置页面,应该会看到字段显示为文本区域、切换开关和切换组。

截图:自定义字段UI组件

如果你需要的不仅仅是内置的UI组件,你可以使用自己的自定义组件。这允许你使用配置来驱动设置页面,而不受可用UI组件的限制。

请参阅文档以了解如何操作以及当前有哪些内置组件可用。新的组件会随着时间的推移而添加!

配置表单布局

此时,你拥有了与之前相同的控件,但布局不同。字段没有分组到面板下,字体大小控件默认也没有隐藏。

DataForm不仅允许你使用配置定义字段,还可以配置用于显示它们的整体布局。

将字段分组到部分

要重新创建之前的布局,请将字段分组到不同的部分。为此,请按如下方式更新settings-page.jsx中的form变量:

const SettingsPage = () => {
    // ...
    const form = {
        fields: [
            {
                id: 'bar',
                label: __( 'Bar', 'unadorned-announcement-bar' ),
                children: [ 'message', 'display' ],
            },
            {
                id: 'appearance',
                label: __( 'Appearance', 'unadorned-announcement-bar' ),
                children: [ 'size' ],
            },
        ],
    };

    // ..
};

配置需要一个id和一个label,就像字段定义一样。但是,不是定义type,而是将现有字段分配为children

如果你刷新设置,可以看到字段被分成了两个部分。

截图:字段分组到“Bar”和“Appearance”部分。

切换布局类型

默认情况下,DataForm使用regular布局,这是隐式的,它将字段一个接一个地排列在单独的行中。但是,还有其他可用的布局:panelcardrow

卡片布局最接近“原始设计”,但也可以尝试其他布局,看看它们的外观!

要切换到卡片布局,请按如下方式更新settings-page.jsxform的配置:

const SettingsPage = () => {
    // ...
    const form = {
        fields: [
            {
                id: 'bar',
                // ...
                layout: { type: 'card' },
            },
            {
                id: 'appearance',
                // ...
                layout: { type: 'card' },
            },
        ],
    };

    // ..
};

如果适合你,你甚至可以分别为每个组混合和匹配布局类型,从而创建各种组合。

截图:将布局类型切换为‘card’

调整布局选项

根据布局,你可以指定其他设置。

例如,对于card布局,你可以控制是否显示标题,或者卡片本身默认是展开还是折叠。要查看每种类型的所有选项,请查看文档

要从第一个组中移除标题并使第二个组默认折叠,请按如下方式修改layout配置:

const SettingsPage = () => {
    // ...
    const form = {
        fields: [
            {
                id: 'bar',
                // ...
                layout: { type: 'card', withHeader: false },
            },
            {
                id: 'appearance',
                // ...
                layout: { type: 'card', isOpened: false },
            },
        ],
    };

    // ..
};

进行此更改后,如果你刷新设置页面,UI将与之前存在的界面非常接近。

截图:修改‘card’布局类型

某些元素的间距和宽度仍需要微调,但这些问题可以通过使用VStack和自定义CSS来解决。

只需几行代码,你就可以完善这些细节以达到最终结果:

由于编写CSS超出了本文的整体范围,请参考GitHub仓库以查看其实现方式。

DataForm连接到settings状态

设置页面已渲染,但它仍然使用传递给DataForm的硬编码data,并且onChange尚未实现:

const SettingsPage = () => {
    const {
        // ...
    } = useSettings();

    const data = {
        message: '',
        display: false,
        size: 'small',
    };
    // ...

    return (
        <>
            <SettingsTitle />
            <Notices />
            <DataForm
                data={ data }
                fields={ fields }
                form={ form }
                onChange={ () => {} }
            />
            <SaveButton onClick={ saveSettings } />
        </>
    );
};

最后一步是将DataForm与处理状态管理的useSettings自定义Hook连接起来。

重构useSettings Hook

目前,字段的状态使用三个useState调用单独存储,但实际设置是作为对象在unadorned_announcement_bar键下获取和保存的。

作为参考,以下是当前自定义Hook在/src/hooks/use-settings.js中的代码:

const useSettings = () => {
const [ message, setMessage ] = useState();
const [ display, setDisplay ] = useState();
const [ size, setSize ] = useState();

const { createSuccessNotice } = useDispatch( noticesStore );

useEffect( () => {
apiFetch( { path: '/wp/v2/settings' } ).then( ( wpSettings ) => {
setMessage( wpSettings.unadorned_announcement_bar.message );
setDisplay( wpSettings.unadorned_announcement_bar.display );
setSize( wpSettings.unadorned_announcement_bar.size );
} );
}, [] );

const saveSettings = () => {
apiFetch( {
path: '/wp/v2/settings