• Hi,

    I’m working on a custom block and using the transforms API to allow it to convert into other blocks. The docs show that you can list multiple block types in the blocks array, but I’m unsure how to handle different logic for each target.

    Here’s a simplified example:

    registerBlockType( 'my/block', {
    title: 'My Block',
    category: 'widgets',
    attributes: {
    content: { type: 'string' },
    },

    transforms: {
    to: [
    {
    type: 'block',
    blocks: [ 'core/paragraph', 'core/heading' ],
    transform: ( attributes ) => {
    // How do I know if the user picked "Paragraph" or "Heading" here?
    return createBlock( 'core/paragraph', {
    content: attributes.content,
    } );
    },
    },
    ],
    },
    } );

    My question:

    • When I provide multiple block names in the blocks array, is there a way inside the transform function to know which block type the user selected?
    • Or is the recommended approach to declare separate transform objects for each target block instead (one for core/paragraph, one for core/heading)?

    I didn’t see this clarified in the Block Transforms documentation.

    Thanks for any guidance!

Viewing 3 replies - 1 through 3 (of 3 total)
  • That’s a great question. It’s one of the slightly confusing parts of the transforms API.

    The short answer is: with the structure you’re using, you don’t know which one the user picked. When you put multiple blocks inside a single transform object’s blocks array, you’re essentially telling Gutenberg that this one transform function is generic enough to handle all of them, which isn’t what you want here.

    To run different logic for each target block, you need to provide a separate transform object for each block inside the to array.

    Here is how you should structure your code:

    JavaScript

    registerBlockType( 'my/block', {
        title: 'My Block',
        category: 'widgets',
        attributes: {
            content: { type: 'string' },
        },
    
        transforms: {
            to: [
                {
                    type: 'block',
                    blocks: [ 'core/paragraph' ], // Only paragraph here
                    transform: ( attributes ) => {
                        // This logic only runs when transforming TO a Paragraph
                        return createBlock( 'core/paragraph', {
                            content: attributes.content,
                        } );
                    },
                },
                {
                    type: 'block',
                    blocks: [ 'core/heading' ], // Only heading here
                    transform: ( attributes ) => {
                        // This logic only runs when transforming TO a Heading
                        return createBlock( 'core/heading', {
                            content: attributes.content,
                            // You could add other default attributes here
                            // level: 2, 
                        } );
                    },
                },
            ],
        },
    } );

    This is expected behavior with the block transforms API.

    When you list multiple block names in the blocks array, the transform() callback does not receive any information about which block type the user selected. By the time the function runs, WordPress has already matched the transform internally.

    So inside a single transform object, there is no reliable way to branch logic based on the chosen block.

    Recommended approach:
    Define separate transform objects for each target block. That is the same pattern used by core blocks and it keeps the logic clear and predictable.

    Example:

    transforms: { to: [ { type: 'block', blocks: [ 'core/paragraph' ], transform: ( attributes ) => { return createBlock( 'core/paragraph', { content: attributes.content, } ); }, }, { type: 'block', blocks: [ 'core/heading' ], transform: ( attributes ) => { return createBlock( 'core/heading', { content: attributes.content, level: 2, } ); }, }, ], },

    This avoids guesswork and makes future maintenance easier.

    On a side note, when working on different projects including Smart Square Wellstar, I have found that keeping logic explicit rather than bundled together saves time long term. The same idea applies here.

    Hope this clarifies things 👍

    When you list multiple block names in the blocks array, WordPress doesn’t pass any information into the transform() callback about which one the user clicked. The transform function only receives the source block’s attributes, not the chosen destination block type. So inside that single transform, there’s no reliable way to detect whether the user selected Paragraph or Heading.

    Because of that, the recommended and most predictable approach is to define separate transform objects, one per target block. That way, each transform has its own logic and explicitly creates the correct block.

    For example:

    transforms: { to: [ { type: 'block', blocks: [ 'core/paragraph' ], transform: ( attributes ) => { return createBlock( 'core/paragraph', { content: attributes.content, } ); }, }, { type: 'block', blocks: [ 'core/heading' ], transform: ( attributes ) => { return createBlock( 'core/heading', { content: attributes.content, level: 2, } ); }, }, ], },

    This makes the behavior clear, avoids guesswork, and keeps the code easier to maintain as your block grows.

    Think of it a bit like an SRD status check system — you don’t use one generic response for every possible outcome. Each status (approved, pending, declined) has its own clear handling. Block transforms work best the same way: one clear path per target, rather than trying to infer the user’s choice after the fact.

    • This reply was modified 4 months, 3 weeks ago by juniorrr.
    • This reply was modified 4 months, 3 weeks ago by juniorrr.
Viewing 3 replies - 1 through 3 (of 3 total)

You must be logged in to reply to this topic.