# Transforms

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.

## Transform direction: `to` and `from`

A 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:

``` js
export const settings = {
    title: 'My Block Title',
    description: 'My block description',
    /* ... */
    transforms: {
        from: [
            /* supported from transforms */
        ],
        to: [
            /* supported to transforms */
        ],
    },
};
```

## Transformations types

This section goes through the existing types of transformations blocks support:

- block
- enter
- files
- prefix
- raw
- shortcode

### Block

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:

- **type** *(string)*: the value `block`.
- **blocks** *(array)*: a list of known block types. It also accepts the wildcard value (`"*"`), meaning that the transform is available to *all* block types (eg: all blocks can transform into `core/group`).
- **transform** *(function)*: a callback that receives the attributes and inner blocks of the block being processed. It should return a block object or an array of block objects.
- **variationName** *(string, optional)*: the name of the target block variation when the transform creates a variation of the transformed block type. This lets the transform UI show the variation title and icon instead of the base block type.
- **isMatch** *(function, optional)*: a callback that receives the block attributes as the first argument and the block object as the second argument and should return a boolean. Returning `false` from this function will prevent the transform from being available and displayed as an option to the user.
- **isMultiBlock** *(boolean, optional)*: whether the transformation can be applied when multiple blocks are selected. If true, the `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.
- **priority** *(number, optional)*: controls the priority with which a transformation is applied, where a lower value will take precedence over higher values. This behaves much like a [WordPress hook](https://developer.wordpress.org/reference/#Hook_to_WordPress). Like hooks, the default priority is `10` when not otherwise set.
- **shortcuts** *(array, optional)*: keyboard shortcuts that apply the transform to the selected block. See [Keyboard shortcuts](#keyboard-shortcuts) below.

#### Keyboard shortcuts

A transform of type `block` can declare keyboard shortcuts, which are registered with the editor’s keyboard shortcuts store and listed in the keyboard shortcuts help modal. Pressing the key combination transforms the selected block, as long as the block is fully editable.

Each entry of `shortcuts` takes the following parameters:

- **name** *(string)*: a unique and machine-readable shortcut name, e.g. `core/block-editor/transform-heading-to-paragraph`.
- **description** *(string)*: a translated description, displayed in the keyboard shortcuts help modal.
- **keyCombination** *(object)*: the key combination that triggers the shortcut, as a `character` and an optional `modifier` (one of the modifiers supported by the [`wp-keycodes` package](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-keycodes/), e.g. `access` or `primary`).
- **aliases** *(array, optional)*: alternative key combinations that trigger the same shortcut.
- **variationName** *(string, optional)*: the variation of the produced block the shortcut targets, defaulting to the transform’s own `variationName`. Declaring it per shortcut is what lets a single transform offer one shortcut per variation without appearing more than once in the block switcher.

On a `to` transform the shortcuts apply to the block declaring them, and produce the first entry of `blocks`. On a `from` transform they apply to any block listed in `blocks`, and produce the block declaring them.

**Example: transform a Heading block into a Paragraph block with <span class="kbd">Alt</span>+<span class="kbd">Shift</span>+<span class="kbd">0</span>**

``` js
transforms: {
    to: [
        {
            type: 'block',
            blocks: [ 'core/paragraph' ],
            shortcuts: [
                {
                    name: 'core/block-editor/transform-heading-to-paragraph',
                    description: __(
                        'Transform the selected heading into a paragraph.'
                    ),
                    keyCombination: { modifier: 'access', character: '0' },
                },
            ],
            transform: ( { content } ) => {
                return createBlock( 'core/paragraph', { content } );
            },
        },
    ],
},
```

**Example: transform any block into a specific heading level**

The Heading block hangs one shortcut per level on its single transform from Paragraph, so that <span class="kbd">Alt</span>+<span class="kbd">Shift</span>+<span class="kbd">2</span> on a paragraph produces an H2 while the block switcher still offers “Heading” once:

``` js
transforms: {
    from: [
        {
            type: 'block',
            blocks: [ 'core/paragraph' ],
            shortcuts: [ 1, 2, 3, 4, 5, 6 ].map( ( level ) => ( {
                name: `core/block-editor/transform-to-heading-${ level }`,
                description: /* … */,
                keyCombination: { modifier: 'access', character: `${ level }` },
                variationName: `h${ level }`,
            } ) ),
            transform: ( { content } ) =>
                createBlock( 'core/heading', { content } ),
        },
    ],
},
```

Key combinations are matched globally, so a combination already claimed by another block or by the editor itself will not reliably reach your transform. In development builds a warning is logged when two blocks declare the same combination.

To switch between variations of a block that is *already* of the target type, declare the shortcut on the [block variation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-variations/#using-shortcut) instead. A shortcut that should do both — reach the variation from another block type and switch to it within the type — is declared in both places under the same `name`.

**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](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-blocks/#createblock).

``` js
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.

``` js
transforms: {
    to: [
        {
            type: 'block',
            blocks: [ 'some/block-with-innerblocks' ],
            transform: ( attributes, innerBlocks ) => {
                return createBlock(
                    'some/other-block-with-innerblocks',
                    attributes,
                    innerBlocks
                );
            },
        },
    ],
},
```

### Enter

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:

- **type** *(string)*: the value `enter`.
- **regExp** *(RegExp)*: the Regular Expression to use as a matcher. If the value matches, the transformation will be applied.
- **transform** *(function)*: a callback that receives an object with a `content` field containing the value that has been entered. It should return a block object or an array of block objects.
- **priority** *(number, optional)*: controls the priority with which a transform is applied, where a lower value will take precedence over higher values. This behaves much like a [WordPress hook](https://developer.wordpress.org/reference/#Hook_to_WordPress). Like hooks, the default priority is `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:

``` js
transforms = {
    from: [
        {
            type: 'enter',
            regExp: /^-{3,}$/,
            transform: () => createBlock( 'core/separator' ),
        },
    ],
};
```

### Files

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:

- **type** *(string)*: the value `files`.
- **transform** *(function)*: a callback that receives the array of files being processed. It should return a block object or an array of block objects.
- **isMatch** *(function, optional)*: a callback that receives the array of files being processed and should return a boolean. Returning `false` from this function will prevent the transform from being applied.
- **priority** *(number, optional)*: controls the priority with which a transform is applied, where a lower value will take precedence over higher values. This behaves much like a [WordPress hook](https://developer.wordpress.org/reference/#Hook_to_WordPress). Like hooks, the default priority is `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:

``` js
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,
                } );
            },
        },
    ],
}
```

### Prefix

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:

- **type** *(string)*: the value `prefix`.
- **prefix** *(string)*: the character or sequence of characters that match this transform.
- **transform** *(function)*: a callback that receives the content introduced. It should return a block object or an array of block objects.
- **priority** *(number, optional)*: controls the priority with which a transform is applied, where a lower value will take precedence over higher values. This behaves much like a [WordPress hook](https://developer.wordpress.org/reference/#Hook_to_WordPress). Like hooks, the default priority is `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:

``` js
transforms: {
    from: [
        {
            type: 'prefix',
            prefix: '?',
            transform( content ) {
                return createBlock( 'my-plugin/question', {
                    content,
                } );
            },
        },
    ],
}
```

### Raw

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:

- **type** *(string)*: the value `raw`.
- **transform** *(function, optional)*: a callback that receives the node being processed. It should return a block object or an array of block objects.
- **schema** *(object\|function, optional)*: defines an [HTML content model](https://html.spec.whatwg.org/multipage/dom.html#content-models) used to detect and process pasted contents. See [below](#schemas-and-content-models).
- **selector** *(string, optional)*: a CSS selector string to determine whether the element matches according to the [element.matches](https://developer.mozilla.org/en-US/docs/Web/API/Element/matches) method. The transform won’t be executed if the element doesn’t match. This is a shorthand and alternative to using `isMatch`, which, if present, will take precedence.
- **isMatch** *(function, optional)*: a callback that receives the node being processed and should return a boolean. Returning `false` from this function will prevent the transform from being applied.
- **priority** *(number, optional)*: controls the priority with which a transform is applied, where a lower value will take precedence over higher values. This behaves much like a [WordPress hook](https://developer.wordpress.org/reference/#Hook_to_WordPress). Like hooks, the default priority is `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:

``` js
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(),
                } );
            },
        },
    ],
}
```

#### Schemas and Content Models

When pasting content it’s possible to define a [content model](https://html.spec.whatwg.org/multipage/dom.html#content-models) 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`](https://github.com/wordpress/gutenberg/blob/trunk/packages/dom/src/dom/clean-node-list.ts); check there for a [complete description of the schema](https://github.com/wordpress/gutenberg/blob/trunk/packages/dom/src/dom/types.ts).

``` js
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.

``` html
<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.

``` js
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.

### Shortcode

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:

- **type** *(string)*: the value `shortcode`.
- **tag** *(string\|array)*: the shortcode tag or list of shortcode aliases this transform can work with.
- **transform** *(function, optional)*: a callback that receives the shortcode attributes as the first argument and the [WPShortcodeMatch](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-shortcode/#next) as the second. It should return a block object or an array of block objects. When this parameter is defined, it will take precedence over the `attributes` parameter.
- **attributes** *(object, optional)*: object representing where the block attributes should be sourced from, according to the attributes shape defined by the [block configuration object](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/). If a particular attribute contains a `shortcode` key, it should be a function that receives the shortcode attributes as the first arguments and the [WPShortcodeMatch](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-shortcode/#next) as second, and returns a value for the attribute that will be sourced in the block’s comment.
- **isMatch** *(function, optional)*: a callback that receives the shortcode attributes per the [Shortcode API](https://codex.wordpress.org/Shortcode_API) and should return a boolean. Returning `false` from this function will prevent the shortcode to be transformed into this block.
- **priority** *(number, optional)*: controls the priority with which a transform is applied, where a lower value will take precedence over higher values. This behaves much like a [WordPress hook](https://developer.wordpress.org/reference/#Hook_to_WordPress). Like hooks, the default priority is `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.

``` js
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.

``` js
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';
            },
        },
    ]
},
```

**Example: shortcode with wrapped content to block with InnerBlocks**

Shortcodes that wrap inner content (e.g. `[example]<p>Inner.</p>[/example]`) can be transformed into a block with InnerBlocks by passing `match.shortcode.content` through [`rawHandler`](https://developer.wordpress.org/block-editor/reference-guide/packages/packages-blocks/#rawhandler) inside `transform`.

``` js
transforms: {
    from: [
        {
            type: 'shortcode',
            tag: 'example',
            transform( attrs, match ) {
                const innerBlocks = rawHandler( {
                    HTML: match.shortcode.content || '',
                } );
                return createBlock(
                    'myplugin/example',
                    { att1: attrs.named.att1 || '' },
                    innerBlocks
                );
            },
        },
    ],
},
```

`rawHandler` recurses into the content, so nested shortcodes and HTML are converted to blocks the same way pasted content is.

## `ungroup` blocks

Via 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:

``` js
export const settings = {
    title: 'My grouping Block Title',
    description: 'My grouping block description',
    /* ... */
    transforms: {
        ungroup: ( attributes, innerBlocks ) =>
            innerBlocks.flatMap( ( innerBlock ) => innerBlock.innerBlocks ),
    },
};
```