Block Transforms API 允许块与其他块或实体(如短代码、文件、正则表达式和原始 DOM 节点)之间进行转换。转换方向包括“从”(from)和“到”(to),通过块配置中的 transforms 键定义。
// 示例:从 Paragraph 块转换为 Heading 块
transforms: {
from: [
{
type: 'block',
blocks: [ 'core/paragraph' ],
transform: ( { content } ) => {
return createBlock( 'core/heading', {
content,
} );
},
},
]
},
// 示例:使用 enter 类型创建 Separator 块
transforms: {
from: [
{
type: 'enter',
regExp: /^-{3,}$/,
transform: () => createBlock( 'core/separator' ),
},
],
};
// 示例:ungroup 转换
transforms: {
ungroup: ( attributes, innerBlocks ) =>
innerBlocks.flatMap( ( innerBlock ) => innerBlock.innerBlocks ),
};Block Transforms is the API that allows a block to be transformed from and to other blocks, as well as from other entities. Existing entities that work with this API include shortcodes, files, regular expressions, and raw DOM nodes.
to and fromA block declares which transformations it supports via the optional transforms key of the block configuration, whose subkeys to and from hold an array of available transforms for every direction. Example:
export const settings = {
title: 'My Block Title',
description: 'My block description',
/* ... */
transforms: {
from: [
/* supported from transforms */
],
to: [
/* supported to transforms */
],
},
};
This section goes through the existing types of transformations blocks support:
This type of transformations support both from and to directions, allowing blocks to be converted into a different one. It has a corresponding UI control within the block toolbar.
A transformation of type block is an object that takes the following parameters:
block."*"), meaning that the transform is available to all block types (eg: all blocks can transform into core/group).false from this function will prevent the transform from being available and displayed as an option to the user.transform function’s first parameter will be an array containing each selected block’s attributes, and the second an array of each selected block’s inner blocks. False by default.10 when not otherwise set.Example: from Paragraph block to Heading block
To declare this transformation we add the following code into the heading block configuration, which uses the createBlock function from the wp-blocks package.
transforms: {
from: [
{
type: 'block',
blocks: [ 'core/paragraph' ],
transform: ( { content } ) => {
return createBlock( 'core/heading', {
content,
} );
},
},
]
},
Example: blocks that have InnerBlocks
A block with InnerBlocks can also be transformed from and to another block with InnerBlocks.
transforms: {
to: [
{
type: 'block',
blocks: [ 'some/block-with-innerblocks' ],
transform: ( attributes, innerBlocks ) => {
return createBlock(
'some/other-block-with-innerblocks',
attributes,
innerBlocks
);
},
},
],
},
This type of transformations support the from direction, allowing blocks to be created from some content introduced by the user. They’re applied in a new block line after the user has introduced some content and hit the ENTER key.
A transformation of type enter is an object that takes the following parameters:
enter.content field containing the value that has been entered. It should return a block object or an array of block objects.10 when not otherwise set.Example: from — to Separator block
To create a separator block when the user types the hyphen three times and then hits the ENTER key we can use the following code:
transforms = {
from: [
{
type: 'enter',
regExp: /^-{3,}$/,
transform: () => createBlock( 'core/separator' ),
},
],
};
This type of transformations support the from direction, allowing blocks to be created from files dropped into the editor.
A transformation of type files is an object that takes the following parameters:
files.false from this function will prevent the transform from being applied.10 when not otherwise set.Example: from file to File block
To create a File block when the user drops a file into the editor we can use the following code:
transforms: {
from: [
{
type: 'files',
isMatch: ( files ) => files.length === 1,
// By defining a lower priority than the default of 10,
// we make that the File block to be created as a fallback,
// if no other transform is found.
priority: 15,
transform: ( files ) => {
const file = files[ 0 ];
const blobURL = createBlobURL( file );
// File will be uploaded in componentDidMount()
return createBlock( 'core/file', {
href: blobURL,
fileName: file.name,
textLinkHref: blobURL,
} );
},
},
];
}
This type of transformations support the from direction, allowing blocks to be created from some text typed by the user. They’re applied when, in a new block line, the user types some text and then adds a trailing space.
A transformation of type prefix is an object that takes the following parameters:
prefix.10 when not otherwise set.Example: from text to custom block
If we want to create a custom block when the user types the question mark, we could use this code:
transforms: {
from: [
{
type: 'prefix',
prefix: '?',
transform( content ) {
return createBlock( 'my-plugin/question', {
content,
} );
},
},
];
}
This type of transformation supports the from direction, allowing blocks to be created from raw HTML nodes. They’re applied when the user executes the “Convert to Blocks” action from within the block setting UI menu, as well as when some content is pasted or dropped into the editor.
A transformation of type raw is an object that takes the following parameters:
raw.isMatch, which, if present, will take precedence.false from this function will prevent the transform from being applied.10 when not otherwise set.Example: from URLs to Embed block
If we want to create an Embed block when the user pastes some URL in the editor, we could use this code:
transforms: {
from: [
{
type: 'raw',
isMatch: ( node ) =>
node.nodeName === 'P' &&
/^s*(https?://S+)s*$/i.test( node.textContent ),
transform: ( node ) => {
return createBlock( 'core/embed', {
url: node.textContent.trim(),
} );
},
},
],
}
When pasting content it’s possible to define a content model that will be used to validate and process pasted content. It’s often the case that HTML pasted into the editor will contain a mixture of elements that should transfer as well as elements that shouldn’t. For example, consider pasting <span class="time">12:04 pm</span> into the editor. We want to copy 12:04 pm and omit the <span> and its class attribute because those won’t carry the same meaning or structure as they originally did from where they were copied.
When writing raw transforms you can control this by supplying a schema which describes allowable content and which will be applied to clean up the pasted content before attempting to match with your block. The schemas are passed into cleanNodeList from @wordpress/dom; check there for a complete description of the schema.
schema = { span: { children: { '#text': {} } } };
Example: a custom content model
Suppose we want to match the following HTML snippet and turn it into some kind of custom post preview block.
<div data-post-id="13">
<h2>The Post Title</h2>
<p>Some <em>great</em> content.</p>
</div>
We want to tell the editor to allow the inner h2 and p elements. We do this by supplying the following schema. In this example we’re using the function form, which accepts an argument supplying phrasingContentSchema (as well as a boolean isPaste indicating if the transformation operation started with pasting text). The phrasingContentSchema is pre-defined to match HTML phrasing elements, such as <strong> and <sup> and <kbd>. Anywhere we expect
a <RichText /> component is a good place to allow phrasing content otherwise we’ll lose all text formatting on conversion.
schema = ({ phrasingContentSchema }) => {
div: {
required: true,
attributes: [ 'data-post-id' ],
children: {
h2: { children: phrasingContentSchema },
p: { children: phrasingContentSchema }
}
}
}
When we successfully match this content every HTML attribute will be stripped away except for data-post-id and if we have other arrangements of HTML inside of a given div then it won’t match our transformer. Likewise we’d fail to match if we found an <h3> in there instead of an <h2>.
Schemas are most-important when wanting to match HTML snippets containing non-phrasing content, such as <details> with a <summary>. Without declaring the custom schema the editor will skip over these other constructions before attempting to run them through any block transforms.
This type of transformations support the from direction, allowing blocks to be created from shortcodes. It’s applied as part of the raw transformation process.
A transformation of type shortcode is an object that takes the following parameters:
shortcode.attributes parameter.shortcode key, it should be a function that receives the shortcode attributes as the first arguments and the WPShortcodeMatch as second, and returns a value for the attribute that will be sourced in the block’s comment.false from this function will prevent the shortcode to be transformed into this block.10 when not otherwise set.Example: from shortcode to block using transform
An existing shortcode can be transformed into its block counterpart using the transform method.
transforms: {
from: [
{
type: 'shortcode',
tag: 'video',
transform( { named: { src } } ) {
return createBlock( 'core/video', { src } );
},
// Prevent the shortcode to be converted
// into this block when it doesn't
// have the proper ID.
isMatch( { named: { id } } ) {
return id === 'my-id';
},
},
],
},
Example: from shortcode to block using attributes
An existing shortcode can be transformed into its block counterpart using the attributes parameters.
transforms: {
from: [
{
type: 'shortcode',
tag: 'youtube',
attributes: {
url: {
type: 'string',
source: 'attribute',
attribute: 'src',
selector: 'img',
},
align: {
type: 'string',
// The shortcode function will extract
// the shortcode atts into a value
// to be sourced in the block's comment.
shortcode: ( { named: { align = 'alignnone' } } ) => {
return align.replace( 'align', '' );
},
},
},
// Prevent the shortcode to be converted
// into this block when it doesn't
// have the proper ID.
isMatch( { named: { id } } ) {
return id === 'my-id';
},
},
]
},
ungroup blocksVia the optional transforms key of the block configuration, blocks can use the ungroup subkey to define the blocks that will replace the block being processed. These new blocks will usually be a subset of the existing inner blocks, but could also include new blocks.
If a block has an ungroup transform, it is eligible for ungrouping, without the requirement of being the default grouping block. The UI used to ungroup a block with this API is the same as the one used for the default grouping block. In order for the Ungroup button to be displayed, we must have a single grouping block selected, which also contains some inner blocks.
ungroup is a callback function that receives the attributes and inner blocks of the block being processed. It should return an array of block objects.
Example:
export const settings = {
title: 'My grouping Block Title',
description: 'My grouping block description',
/* ... */
transforms: {
ungroup: ( attributes, innerBlocks ) =>
innerBlocks.flatMap( ( innerBlock ) => innerBlock.innerBlocks ),
},
};