WordPress 提供了几个 API,允许你修改现有块的行为。

注册

WordPress 中的块通常使用 block.json 元数据在服务器端和客户端进行注册。你可以使用以下过滤器在服务器端使用 PHP、在客户端使用 JavaScript 修改或扩展块的设置。欲了解更多信息,请参阅 块注册 指南。

block_type_metadata

过滤从 block.json 文件加载的原始元数据,当使用 PHP 在服务器上注册块类型时。它允许在元数据处理之前应用修改。

此过滤器的回调函数接收一个参数:

  • $metadata (array): 从 block.json 加载的用于注册块类型的元数据。

以下示例将所有块的 apiVersion 设置为 2。

function example_filter_metadata_registration( $metadata ) {
    $metadata['apiVersion'] = 2;
    return $metadata;
};
add_filter( 'block_type_metadata', 'example_filter_metadata_registration' );

这是一个更稳健的示例,它禁用了标题块的背景色和渐变支持。block_type_metadata 过滤器非常适合 定制编辑器体验。

function example_disable_heading_background_color_and_gradients( $metadata ) {

    // Only apply the filter to Heading blocks.
    if ( ! isset( $metadata['name'] ) || 'core/heading' !== $metadata['name'] ) {
        return $metadata;
    }

    // Check if 'supports' key exists.
    if ( isset( $metadata['supports'] ) && isset( $metadata['supports']['color'] ) ) {

        // Remove Background color and Gradients support.
        $metadata['supports']['color']['background'] = false;
        $metadata['supports']['color']['gradients']  = false;
    }

    return $metadata;
}
add_filter( 'block_type_metadata', 'example_disable_heading_background_color_and_gradients' );

block_type_metadata_settings

过滤从处理的块类型元数据确定的设置。它使得可以使用默认处理程序不处理的块元数据应用自定义修改成为可能。

此过滤器的回调函数接收两个参数:

  • $settings (array): 用于注册块类型的确定设置数组。
  • $metadata (array): 从 block.json 文件加载的元数据。

以下示例将所有块的 apiVersion 增加 1。

function example_filter_metadata_registration( $settings, $metadata ) {
    $settings['api_version'] = $metadata['apiVersion'] + 1;
    return $settings;
};
add_filter( 'block_type_metadata_settings', 'example_filter_metadata_registration', 10, 2 );

register_block_type_args

在块类型在服务器上正式注册之前,过滤块的参数数组 ($args)。

此过滤器的回调函数接收两个参数:

  • $args (array): 用于注册块类型的参数数组。
  • $block_type (string): 包含命名空间的块类型名称。

register_block_type_args 是可用的最低级别的 PHP 过滤器,它将适用于在服务器上注册的每个块。在服务器上定义的所有设置都会以比客户端设置的更高优先级传播到客户端。

以下代码将禁用段落、标题、列表和列表项块的颜色控件。

function example_disable_color_for_specific_blocks( $args, $block_type ) {

    // List of block types to modify.
    $block_types_to_modify = [
        'core/paragraph',
        'core/heading',
        'core/list',
        'core/list-item'
    ];

    // Check if the current block type is in the list.
    if ( in_array( $block_type, $block_types_to_modify, true ) ) {
        // Disable color controls.
        $args['supports']['color'] = array(
            'text'       => false,
            'background' => false,
            'link'       => false,
        );
    }

    return $args;
}
add_filter( 'register_block_type_args', 'example_disable_color_for_specific_blocks', 10, 2 );

blocks.registerBlockType

用于在客户端使用 JavaScript 注册块时过滤块的设置。它接收块的设置、注册的块名称以及 null 或弃用的块设置(当应用于注册的弃用时)作为参数。此过滤器也适用于块的每个弃用设置。

以下示例确保列表块以规范生成的类名 (wp-block-list) 保存:

function addListBlockClassName( settings, name ) {
    if ( name !== 'core/list' ) {
        return settings;
    }

    return {
        ...settings,
        supports: {
            ...settings.supports,
            className: true,
        },
    };
}

wp.hooks.addFilter(
    'blocks.registerBlockType',
    'my-plugin/class-names/list-block',
    addListBlockClassName
);

前端

以下 PHP 过滤器可用于更改块在前端的输出。

render_block

过滤任何块的前端内容。此过滤器对编辑器中块的行为没有影响。

此过滤器的回调函数接收三个参数:

  • $block_content (string): 块内容。
  • $block (array): 完整的块,包括名称和属性。
  • $instance (WP_Block): 块实例。

在以下示例中,类 example-class 被添加到前端的所有段落块上。这里使用 HTML API 轻松添加类,而不是依赖正则表达式。

function example_add_custom_class_to_paragraph_block( $block_content, $block ) {

    // Check if the block is a Paragraph block.
    if ( 'core/paragraph' === $block['blockName'] ) {

        // Add the custom class to the block content using the HTML API.
        $processor = new WP_HTML_Tag_Processor( $block_content );

        if ( $processor->next_tag( 'p' ) ) {
            $processor->add_class( 'example-class' );
        }

        return $processor->get_updated_html();
    }

    return $block_content;
}
add_filter( 'render_block', 'example_add_custom_class_to_paragraph_block', 10, 2 );

render_block_{namespace/block}

过滤定义的块的前端内容。当你只需要修改特定块类型时,这只是 render_block 的更简单形式。

此过滤器的回调函数接收三个参数:

  • $block_content (string): 块内容。
  • $block (array): 完整的块,包括名称和属性。
  • $instance (WP_Block): 块实例。

在以下示例中,类 example-class 被添加到前端的所有段落块上。请注意,与上面的 render_block 示例相比,你不再需要在修改内容之前检查块类型。同样,使用 HTML API 而不是正则表达式。

function example_add_custom_class_to_paragraph_block( $block_content, $block ) {

    // Add the custom class to the block content using the HTML API.
    $processor = new WP_HTML_Tag_Processor( $block_content );

    if ( $processor->next_tag( 'p' ) ) {
        $processor->add_class( 'example-class' );
    }

    return $processor->get_updated_html();
}
add_filter( 'render_block_core/paragraph', 'example_add_custom_class_to_paragraph_block', 10, 2 );

编辑器

以下 JavaScript 过滤器可用于在编辑器中编辑时更改块的行为。

blocks.getSaveElement

适用于块的 save 函数结果的过滤器。此过滤器用于替换或扩展元素,例如使用 React.cloneElement 修改元素的属性、替换其子元素或返回一个全新的元素。

此过滤器的回调函数接收三个参数:

  • element (Object): 要修改并返回的元素。
  • blockType (Object): 块类型定义对象。
  • attributes (Object): 块的属性。

以下示例将覆盖块包裹在外层容器 div 中。

function wrapCoverBlockInContainer( element, blockType, attributes ) {

    // 如果元素未定义则跳过。
    if ( ! element ) {
        return;
    }

    // 仅应用于 Cover 块。
    if ( blockType.name !== 'core/cover' ) {
        return element;
    }

    // 返回用 div 包装的元素。
    return <div className="cover-block-wrapper">{ element }</div>;
}

wp.hooks.addFilter(
    'blocks.getSaveElement',
    'my-plugin/wrap-cover-block-in-container',
    wrapCoverBlockInContainer
);

blocks.getSaveContent.extraProps

这是一个应用于所有在 save 函数中返回 WP 元素的块的过滤器。此过滤器用于向 save 函数的根元素添加额外属性。例如,您可以添加 className、id 或该元素的任何有效属性。

此过滤器的回调函数接收三个参数:

  • props (Object): 当前要修改并返回的 save 元素的属性。
  • blockType (Object): 块类型定义对象。
  • attributes (Object): 块的属性。

以下示例为所有块默认添加红色背景。

function addBackgroundColorStyle( props ) {
    return {
        ...props,
        style: { backgroundColor: 'red' },
    };
}

wp.hooks.addFilter(
    'blocks.getSaveContent.extraProps',
    'my-plugin/add-background-color-style',
    addBackgroundColorStyle
);

注意: 如果此过滤器在下一次编辑帖子时修改了现有内容,将发生 块验证 错误。编辑器会验证存储在帖子中的内容与 save() 函数输出的内容是否匹配。

为避免此验证错误,请使用 render_block 服务器端来修改现有帖子内容,而不是使用此过滤器。请参阅 render_block 文档。

blocks.getBlockDefaultClassName

生成的块 HTML 类遵循 wp-block-{name} 命名规范。此过滤器允许提供替代类名。

// 我们的过滤器函数。
function setBlockCustomClassName( className, blockName ) {
    return blockName === 'core/code' ? 'my-plugin-code' : className;
}

// 添加过滤器。
wp.hooks.addFilter(
    'blocks.getBlockDefaultClassName',
    'my-plugin/set-block-custom-class-name',
    setBlockCustomClassName
);

blocks.switchToBlockType.transformedBlock

用于过滤块转换的单个转换结果。由于转换是多对多的,而不是单对一的,因此会传递所有原始块。

blocks.getBlockAttributes

在默认解析块的属性后立即调用,并在验证之前调用,以允许插件在验证和/或编辑器中渲染块的初始值时操纵属性值。

此过滤器的回调函数接受 4 个参数:
– blockAttributes (Object): 所有块属性。
– blockType (Object): 块类型。
– innerHTML (string): 原始块内容。
– attributes (object): 已知的块属性(来自分隔符)。

在以下示例中,我们使用 blocks.getBlockAttributes 过滤器来锁定页面上所有段落块的位置。

// 我们的过滤器函数
function lockParagraphs( blockAttributes, blockType, innerHTML, attributes  ) {
    if('core/paragraph' === blockType.name) {
        blockAttributes['lock'] = {move: true}
    }
    return blockAttributes;
}

// 添加过滤器
wp.hooks.addFilter(
    'blocks.getBlockAttributes',
    'my-plugin/lock-paragraphs',
    lockParagraphs
);

editor.BlockEdit

用于修改块的 edit 组件。它接收原始的块 BlockEdit 组件并返回一个新的包装组件。

以下示例为所有块添加新的检查器面板。

const { createHigherOrderComponent } = wp.compose;
const { InspectorControls } = wp.blockEditor;
const { PanelBody } = wp.components;

const withMyPluginControls = createHigherOrderComponent( ( BlockEdit ) => {
    return ( props ) => {
        return (
            <>
                <BlockEdit key="edit" { ...props } />
                <InspectorControls>
                    <PanelBody>My custom control</PanelBody>
                </InspectorControls>
            </>
        );
    };
}, 'withMyPluginControls' );

wp.hooks.addFilter(
    'editor.BlockEdit',
    'my-plugin/with-inspector-controls',
    withMyPluginControls
);

请注意,由于此钩子是为 所有块 运行的,因此使用它可能会导致性能回退,特别是在块选择指标方面。

为了缓解这个问题,请考虑是否可以更改您执行的工作以仅在特定条件下运行。

例如,假设您添加的组件仅在块被 选中 时才需要渲染。在这种情况下,您可以使用块的“选中”状态 (props.isSelected) 来条件化您的渲染。

以下示例为所有块添加新的检查器面板,但仅在块被选中时。

const withMyPluginControls = createHigherOrderComponent( ( BlockEdit ) => {
    return ( props ) => {
        return (
            <>
                <BlockEdit { ...props } />
                { props.isSelected && (
                    <InspectorControls>
                        <PanelBody>My custom control</PanelBody>
                    </InspectorControls>
                ) }
            </>
        );
    };
}, 'withMyPluginControls' );

editor.BlockListBlock

用于修改包含块的 edit 组件和所有工具栏的块的包装组件。它接收原始的 BlockListBlock 组件并返回一个新的包装组件。

以下示例为所有块添加唯一的类名。

const { createHigherOrderComponent } = wp.compose;

const withClientIdClassName = createHigherOrderComponent(
    ( BlockListBlock ) => {
        return ( props ) => {
            return (
                <BlockListBlock
                    { ...props }
                    className={ 'block-' + props.clientId }
                />
            );
        };
    },
    'withClientIdClassName'
);

wp.hooks.addFilter(
    'editor.BlockListBlock',
    'my-plugin/with-client-id-class-name',
    withClientIdClassName
);

您可以使用返回组件的 wrapperProps 属性向块的包装组件添加新属性,如下例所示。

const { createHigherOrderComponent } = wp.compose;
const withMyWrapperProp = createHigherOrderComponent( ( BlockListBlock ) => {
    return ( props ) => {
        const wrapperProps = {
            ...props.wrapperProps,
            'data-my-property': 'the-value',
        };
        return <BlockListBlock { ...props } wrapperProps={ wrapperProps } />;
    };
}, 'withMyWrapperProp' );

wp.hooks.addFilter(
    'editor.BlockListBlock',
    'my-plugin/with-my-wrapper-prop',
    withMyWrapperProp
);

editor.postContentBlockTypes

用于修改即使在锁定模板中使用时也应启用的块列表。任何将数据保存到帖子的块都应添加到此列表中。Post Featured Image 块就是一个例子。该块通常用于模板,即使模板被锁定,也应允许选择图像。

以下示例启用虚构的块 namespace/example。

const addExampleBlockToPostContentBlockTypes = ( blockTypes ) => {
    return [ ...blockTypes, 'namespace/example' ];
};

wp.hooks.addFilter(
    'editor.postContentBlockTypes',
    'my-plugin/post-content-block-types',
    addExampleBlockToPostContentBlockTypes
);

移除块

使用拒绝列表

添加块已经足够简单,而移除它们也同样简单。插件或主题作者可以使用 JavaScript 中的拒绝列表来“注销”块。

将以下代码放在 my-plugin.js 文件中。

// my-plugin.js
import { unregisterBlockType } from '@wordpress/blocks';
import domReady from '@wordpress/dom-ready';

domReady( function () {
    unregisterBlockType( 'core/verse' );
} );

然后,使用以下函数在编辑器中加载此脚本。

<?php
// my-plugin.php

function my_plugin_deny_list_blocks() {
    wp_enqueue_script(
        'my-plugin-deny-list-blocks',
        plugins_url( 'my-plugin.js', __FILE__ ),
        array( 'wp-blocks', 'wp-dom-ready', 'wp-edit-post' )
    );
}
add_action( 'enqueue_block_editor_assets', 'my_plugin_deny_list_blocks' );
在注销一个块时,可能会发生代码运行顺序的竞态条件:是注册块还是注销块。你希望你的注销代码最后运行。为此,你必须将注册该块的组件指定为依赖项,在本例中为 wp-edit-post。此外,使用 wp.domReady() 可确保注销代码在 DOM 加载后运行。

使用允许列表

如果你想禁用所有块,只保留一个允许列表,你可以像这样调整上面的脚本:

// my-plugin.js

var allowedBlocks = [
    'core/paragraph',
    'core/image',
    'core/html',
    'core/freeform',
];

wp.blocks.getBlockTypes().forEach( function ( blockType ) {
    if ( allowedBlocks.indexOf( blockType.name ) === -1 ) {
        wp.blocks.unregisterBlockType( blockType.name );
    }
} );

从插入器中隐藏块

allowed_block_types_all

在 WordPress 5.8 之前,此钩子被称为 allowed_block_types,现已弃用。如果你需要支持旧版本的 WordPress,你可能需要一种方法来检测应使用哪个过滤器。你可以通过检查 WP_Block_Editor_Context 类是否存在来查看是否可以使用 allowed_block_types,该类是在 5.8 中引入的。

在服务器上,你可以使用 allowed_block_types_all 过滤器过滤插入器中显示的块列表。你可以返回 true(支持所有块类型)、false(不支持任何块类型),或允许使用的块类型名称数组。你还可以使用第二个提供的参数 $editor_context 根据其内容过滤块类型。

<?php
// my-plugin.php
function example_filter_allowed_block_types_when_post_provided( $allowed_block_types, $editor_context ) {
    if ( ! empty( $editor_context->post ) ) {
        return array( 'core/paragraph', 'core/heading' );
    }
    return $allowed_block_types;
}
add_filter( 'allowed_block_types_all', 'example_filter_allowed_block_types_when_post_provided', 10, 2 );

管理块类别

block_categories_all

在 WordPress 5.8 之前,此钩子被称为 block_categories,现已弃用。如果你需要支持旧版本的 WordPress,你可能需要一种方法来检测应使用哪个过滤器。你可以通过检查 WP_Block_Editor_Context 类是否存在来查看是否可以使用 block_categories,该类是在 5.8 中引入的。

可以使用 block_categories_all 过滤器过滤默认块类别列表。你可以在服务器上通过实现一个返回类别列表的函数来完成此操作。它将在块注册期间使用,并在插入器中对块进行分组。你还可以使用第二个提供的参数 $editor_context 根据其内容过滤。

// my-plugin.php
function example_filter_block_categories_when_post_provided( $block_categories, $editor_context ) {
    if ( ! empty( $editor_context->post ) ) {
        array_push(
            $block_categories,
            array(
                'slug'  => 'custom-category',
                'title' => __( 'Custom Category', 'custom-plugin' ),
                'icon'  => null,
            )
        );
    }
    return $block_categories;
}
add_filter( 'block_categories_all', 'example_filter_block_categories_when_post_provided', 10, 2 );

wp.blocks.updateCategory

你还可以通过设置 icon 属性来为你的块类别显示图标。该值可以是WordPress Dashicon的slug。

你还可以以 SVG 格式设置自定义图标。为此,图标应在前端渲染并设置,以便利用 WordPress SVG,实现移动兼容性并使图标更易于访问。

要为上一示例中显示的类别设置 SVG 图标,请将以下示例 JavaScript 代码添加到调用 wp.blocks.updateCategory 的编辑器中,例如:

( function () {
    var el = React.createElement;
    var SVG = wp.primitives.SVG;
    var circle = el( 'circle', {
        cx: 10,
        cy: 10,
        r: 10,
        fill: 'red',
        stroke: 'blue',
        strokeWidth: '10',
    } );
    var svgIcon = el(
        SVG,
        { width: 20, height: 20, viewBox: '0 0 20 20' },
        circle
    );
    wp.blocks.updateCategory( 'my-category', { icon: svgIcon } );
} )();