Slot 和 Fill 是暴露出来的组件,旨在允许开发者将项目注入到 Gutenberg 管理体验中的某些预定义位置。
有关更多详细信息,请参阅 SlotFill 组件文档。

为了使用它们,我们必须利用 @wordpress/plugins API 来注册一个插件,该插件将注入我们的项目。

用法概述

为了访问 SlotFills,我们需要做四件事:

  1. 从 @wordpress/plugins 包导入 registerPlugin 方法。
  2. 从 @wordpress/editor' 包导入我们需要的 SlotFill。
  3. 定义一个组件来渲染我们的更改。我们的更改/添加内容将被包裹在我们导入的 SlotFill 组件中。
  4. 注册插件。

以下是使用 PluginPostStatusInfo slotFill 的示例:

import { registerPlugin } from '@wordpress/plugins';
import { PluginPostStatusInfo } from '@wordpress/editor';

const PluginPostStatusInfoTest = () => (
    <PluginPostStatusInfo>
        <p>Post Status Info SlotFill</p>
    </PluginPostStatusInfo>
);

registerPlugin( 'post-status-info-test', { render: PluginPostStatusInfoTest } );

有条件地渲染 SlotFill 内容

除了 MainDashboardButton 之外,所有可用的 SlotFill 都在 Post Editor(帖子编辑器)和 Site Editor(站点编辑器)中暴露出来,并且任何注册的 Fill 都将在两种上下文中呈现。有多种方法可以实现有条件地渲染 Fills。

将 fills 限制在 Post Editor 中

可以通过检查当前 post type 对象属性 viewable 是否设置为 true 来将 fill 限制在 Post Editor 中。任何未设置为 viewable 的 post type 都没有关联的编辑帖子屏幕,这通常表明用户不在 Post Editor 中。下面的示例将在任何已注册的 post type 的编辑帖子屏幕上渲染其内容。

import { registerPlugin } from '@wordpress/plugins';
import {
    PluginDocumentSettingPanel,
    store as editorStore,
} from '@wordpress/editor';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';

/**
 * The component to be rendered  as part of the plugin.
 */
const EditPostDocumentSettingPanel = () => {
    // Retrieve information about the current post type.
    const isViewable = useSelect( ( select ) => {
        const postTypeName = select( editorStore ).getCurrentPostType();
        const postTypeObject = select( coreStore ).getPostType( postTypeName );
        return postTypeObject?.viewable;
    }, [] );

    // If the post type is not viewable, then do not render the plugin.
    if ( ! isViewable ) {
        return null;
    }

    return (
        <PluginDocumentSettingPanel
            name="custom-panel"
            title={ __( 'Post Editor Example' ) }
            className="custom-panel"
        >
            <p>{ __( 'Only appears in the Edit Post screen' ) }</p>
        </PluginDocumentSettingPanel>
    );
};

registerPlugin( 'example-post-edit-only', {
    render: EditPostDocumentSettingPanel,
} );

将 fills 限制在某些 post types 上。

以下示例在上述示例的基础上进行了扩展,创建了一个允许列表,指定了应该渲染 fill 的 post types。在这种情况下,仅在编辑页面时才会渲染 fill。

import { registerPlugin } from '@wordpress/plugins';
import {
    PluginDocumentSettingPanel,
    store as editorStore,
} from '@wordpress/editor';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { __, sprintf } from '@wordpress/i18n';

/**
 * The component to be rendered  as part of the plugin.
 */
const RestrictPostTypes = () => {
    // Retrieve information about the current post type.
    const { isViewable, postTypeName } = useSelect( ( select ) => {
        const postType = select( editorStore ).getCurrentPostType();
        const postTypeObject = select( coreStore ).getPostType( postType );
        return {
            isViewable: postTypeObject?.viewable,
            postTypeName: postType,
        };
    }, [] );

    // The list of post types that are allowed to render the plugin.
    const allowedPostTypes = [ 'page' ];

    // If the post type is not viewable or not in the allowed list, do not render the plugin.
    if ( ! isViewable || ! allowedPostTypes.includes( postTypeName ) ) {
        return null;
    }

    return (
        <PluginDocumentSettingPanel
            name="custom-panel"
            title={ __( 'Restrict Post Types Example' ) }
            className="custom-panel"
        >
            <p>
                { sprintf(
                    __(
                        'Only appears on Post Types that are in the allowed list. %s'
                    ),
                    allowedPostTypes.join( ', ' )
                ) }
            </p>
        </PluginDocumentSettingPanel>
    );
};

registerPlugin( 'example-restrict-post-types', {
    render: RestrictPostTypes,
} );

将 fills 限制在 Side Editor 中

要将 fills 限制在 Site Editor 中,逻辑则相反。如果 post type 对象的 viewable 属性设置为 true,则不应渲染 fill。下面的示例将在任何 Site Editor 屏幕上渲染其内容。

import { registerPlugin } from '@wordpress/plugins';
import {
    PluginDocumentSettingPanel,
    store as editorStore,
} from '@wordpress/editor';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';

/**
 * The component to be rendered  as part of the plugin.
 */
const SiteEditorDocumentSettingPanel = () => {
    // Retrieve information about the current post type.
    const isViewable = useSelect( ( select ) => {
        const postTypeName = select( editorStore ).getCurrentPostType();
        const postTypeObject = select( coreStore ).getPostType( postTypeName );

        // A viewable post type is one than can be viewed in the WordPress admin. Internal ones are not set to viewable.
        return postTypeObject?.viewable;
    }, [] );

    // If the post type is viewable, do not render my fill
    if ( isViewable ) {
        return null;
    }

    return (
        <PluginDocumentSettingPanel
            name="custom-panel"
            title={ __( 'Site Editor Example' ) }
            className="custom-panel"
        >
            <p>{ __( 'Only appears in the Site Editor' ) }</p>
        </PluginDocumentSettingPanel>
    );
};

registerPlugin( 'example-site-editor', {
    render: SiteEditorDocumentSettingPanel,
} );

将 fills 限制在 Site Editor 的特定屏幕上。

此示例在上述示例的基础上构建,提供了一个允许列表来控制 fill 可以在 Site Editor 中的哪些屏幕上渲染。

import { registerPlugin } from '@wordpress/plugins';
import {
    PluginDocumentSettingPanel,
    store as editorStore,
} from '@wordpress/editor';
import { store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { __, sprintf } from '@wordpress/i18n';

/**
 * The component to be rendered  as part of the plugin.
 */
const SiteEditorDocumentSettingPanel = () => {
    // Allowed areas in the Site Editor.
    const allowedSiteEditorScreens = [
        'wp_template', // Templates
        'wp_block', // Patterns
        'wp_template_part', // Template Parts
    ];

    const { isViewable, postType } = useSelect( ( select ) => {
        const postTypeName = select( editorStore ).getCurrentPostType();
        const postTypeObject = select( coreStore ).getPostType( postTypeName );

        return {
            // A viewable post type is one than can be viewed in the WordPress admin. Internal ones are not set to viewable.
            isViewable: postTypeObject?.viewable,
            postType: postTypeName,
        };
    }, [] );

    // If the post type is viewable, do not render my plugin.
    if ( isViewable || ! allowedSiteEditorScreens.includes( postType ) ) {
        return null;
    }

    return (
        <PluginDocumentSettingPanel
            name="custom-panel"
            title={ __( 'Restricted to Site Editor screens' ) }
            className="custom-panel"
        >
            <p>
                { sprintf(
                    __(
                        'Only appears on Editor Screens that are in the allowed list. %s'
                    ),
                    allowedSiteEditorScreens.join( ', ' )
                ) }
            </p>
        </PluginDocumentSettingPanel>
    );
};

registerPlugin( 'example-site-editor-only', {
    render: SiteEditorDocumentSettingPanel,
} );

它们是如何工作的?

SlotFills 是使用 createSlotFill 创建的。这会创建两个组件:Slot 和 Fill,然后用于创建一个新组件,该组件导出在 wp.plugins 全局对象上。

PluginPostStatusInfo SlotFill 的定义(查看核心代码)

/**
 * 为摘要面板定义一个可扩展性插槽。
 */
import { createSlotFill, PanelRow } from '@wordpress/components';

export const { Fill, Slot } = createSlotFill( 'PluginPostStatusInfo' );

const PluginPostStatusInfo = ( { children, className } ) => (
    <Fill>
        <PanelRow className={ className }>{ children }</PanelRow>
    </Fill>
);

PluginPostStatusInfo.Slot = Slot;

export default PluginPostStatusInfo;

这个新的 Slot 随后会在编辑器中暴露出来。下面的示例来自核心代码,代表了摘要面板。

我们可以看到,<PluginPostStatusInfo.Slot> 包裹了所有将出现在面板中的项目。
任何通过 SlotFill 添加的项目(见上面的示例),都会包含在 fills 参数中,并显示在组件的末尾。

参见 核心代码。

export default function PostSummary( { onActionPerformed } ) {
    const { isRemovedPostStatusPanel } = useSelect( ( select ) => {
        // 我们使用 isEditorPanelRemoved 来隐藏如果程序化移除的面板。我们不使用 isEditorPanelEnabled,因为此面板不应通过 UI 禁用。
        const { isEditorPanelRemoved } = select( editorStore );
        return {
            isRemovedPostStatusPanel: isEditorPanelRemoved( PANEL_NAME ),
        };
    }, [] );

    return (
        <PostPanelSection className="editor-post-summary">
            <PluginPostStatusInfo.Slot>
                { ( fills ) => (
                    <>
                        <Stack direction="column" gap="lg">
                            <PostCardPanel
                                onActionPerformed={ onActionPerformed }
                            />
                            <PostFeaturedImagePanel withPanelBody={ false } />
                            <PostExcerptPanel />
                            <Stack direction="column" gap="xs">
                                <PostContentInformation />
                                <PostLastEditedPanel />
                            </Stack>
                            { ! isRemovedPostStatusPanel && (
                                <Stack direction="column" gap="sm">
                                    <Stack direction="column" gap="xs">
                                        <PostStatusPanel />
                                        <PostSchedulePanel />
                                        <PostURLPanel />
                                        <PostAuthorPanel />
                                        <PostTemplatePanel />
                                        <PostDiscussionPanel />
                                        <PageAttributesPanel />
                                        <PostSyncStatus />
                                        <BlogTitle />
                                        <PostsPerPage />
                                        <SiteDiscussion />
                                        <PostFormatPanel />
                                        <PostStickyPanel />
                                    </Stack>
                                    <TemplateAreas />
                                    { fills }
                                </Stack>
                            ) }
                        </Stack>
                    </>
                ) }
            </PluginPostStatusInfo.Slot>
        </PostPanelSection>
    );
}

当前可用的 SlotFills 和示例

以下 SlotFills 在 edit-post 或 editor 包中可用。请参阅下面的各个项目以获取用法和示例详情: