跳转到主要内容

区块过滤器

WordPress 提供了多个 API,允许您修改现有区块的行为。

注册

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

block_type_metadata

Filters the raw metadata loaded from the block.json file when registering a block type on the server with PHP. It allows modifications to be applied before the metadata gets processed.

The callback function for this filter receives one parameter:

  • $metadata (array): Metadata loaded from block.json for registering a block type.

The following example sets the apiVersion of all blocks to 2.

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

Here's a more robust example that disables background color and gradient support for Heading blocks. The block_type_metadata filter is excellent for curating the Editor experience.

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

Filters a block's arguments array ($args) right before the block type is officially registered on the server.

The callback function for this filter receives two parameters:

  • $args (array): Array of arguments for registering a block type.
  • $block_type (string): Block type name including namespace.

register_block_type_args is the most low-level PHP filter available, and it will work for every block registered on the server. All settings defined on the server are propagated to the client with higher priority than those set in the client.

The following code will disable the color controls for Paragraph, Heading, List, and List Item blocks.

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
);

Front end

The following PHP filters are available to change the output of a block on the front end.

render_block

Filters the front-end content of any block. This filter has no impact on the behavior of blocks in the Editor.

The callback function for this filter receives three parameters:

  • $block_content (string): The block content.
  • $block (array): The full block, including name and attributes.
  • $instance (WP_Block): The block instance.

In the following example, the class example-class is added to all Paragraph blocks on the front end. Here the HTML API is used to easily add the class instead of relying on regex.

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}

Filters the front-end content of the defined block. This is just a simpler form of render_block when you only need to modify a specific block type.

The callback function for this filter receives three parameters:

  • $block_content (string): The block content.
  • $block (array): The full block, including name and attributes.
  • $instance (WP_Block): The block instance.

In the following example, the class example-class is added to all Paragraph blocks on the front end. Notice that compared to the render_block example above, you no longer need to check the block type before modifying the content. Again, the HTML API is used instead of regex.

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 );

Editor

The following JavaScript filters are available to change the behavior of blocks while editing in the Editor.

blocks.getSaveElement

A filter that applies to the result of a block's save function. This filter is used to replace or extend the element, for example using React.cloneElement to modify the element's props, replace its children, or return an entirely new element.

The callback function for this filter receives three parameters:

  • element (Object): The element to be modified and returned.
  • blockType (Object): A block-type definition object.
  • attributes (Object): The block's attributes.

The following example wraps a Cover block in an outer container div.

function wrapCoverBlockInContainer( element, blockType, attributes ) {
	
	// Skip if element is undefined.
	if ( ! element ) {
		return;
	}

	// Only apply to Cover blocks.
	if ( blockType.name !== 'core/cover' ) {
		return element;
	}

	// Return the element wrapped in a 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

Used to modify the block's edit component. It receives the original block BlockEdit component and returns a new wrapped component.

The following example adds a new Inspector panel for all blocks.

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
);

Note that as this hook is run for all blocks, consuming it has the potential for performance regressions, particularly around block selection metrics.

To mitigate this, consider whether any work you perform can be altered to run only under certain conditions.

For example, suppose you are adding components that only need to render when the block is selected. In that case, you can use the block's "selected" state (props.isSelected) to conditionalize your rendering.

The following example adds a new Inspector panel for all blocks, but only when a block is selected.

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

用于修改即使在锁定模板内部使用时也应启用的区块列表。任何将数据保存到文章的区块都应添加至此。例如“文章特色图片”区块。该区块常用于模板中,即使模板被锁定,仍应允许选择图片。

以下示例启用了虚构区块 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 的别名。

您也可以设置一个 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 } );
} )();