0

I am creating a block which is created when transformed from a shortcode. In other words, this:

[example att1="foo" att2="bar"]
    <p>Inner.</p>
    <p>Content.</p>
[/example]

should transform into this a myplugin/example block with inner blocks of the two p tags.

So far I've got this, which works fine to get the shortcode attributes.

(function(wp){

    wp.blocks.registerBlockType( 'myplugin/example', {
        ...

        attributes: {
            att1 {
                type: 'string',
                default: '',
            },
            att2: {
                type: 'string',
                default: '',
            },
        }, 

        transforms: {
            from: [
                {
                    type: 'shortcode',
                    tag: 'example',
                    attributes: {
                        att1: {
                            type: 'string',
                            shortcode: attributes => {
                                return attributes.named.att1 || '';
                            }
                        },
                        att2: {
                            type: 'string',
                            shortcode: attributes => {
                                return attributes.named.att2 || '';
                            },
                        },
                    },
                },
            ],
        },
        ...

I can get the content by looking at the second parameter in one of those attributes shortcode functions:

attributes: {
    att1: {
        shortcode: (attributes, data) => {
             // data.shortcode.content is the shortcode's inner content
        }
    }
}

But I don't know how to insert that content as innerBlocks in the output block. The block registration "transforms" attribute documentation is not helpful in this area.

I've tried using the transform attribute in the block definition, but that doesn't seem to work.

1 Answer 1

1

There is no built-in solution to use a shortcode's inner content as a new block's innerBlocks. The best I was able to do is a two step process which first transforms a raw shortcode to the core shortcode block, then transform that into the new block. In that way I was able to use the inner content as innerBlocks.

The reason to do it that way is the "block" transform type has access to a more granular transform function. It ends up looking something like this:


     type: 'block',
     blocks: ['core/shortcode'],
     isMatch: function( {text} ) {
        return /^\[slidetoggle /.test(text);
     },
     transform: ({text}) => {

        const initialStateVal = getAttributeValue('slidetoggle', 'initialstate', text);

        const content = getInnerContent('slidetoggle', text);

        const innerBlocks = wp.blocks.rawHandler({
          HTML: content,
        });

        return wp.blocks.createBlock('example/slidetoggle', {
          initiallyClosed: initiallyClosed,
        }, innerBlocks);
     },
  },

and the getAttributeValue and getInnerContent functions look like this:

export const getAttributeValue = function(tag, att, content){
    var re = new RegExp(`\\[${tag}[^\\]]* ${att}="([^"]*)"`, 'im');
    var result = content.match(re);
    if( result != null && result.length > 0 )
        return result[1];

    re = new RegExp(`\\[${tag}[^\\]]* ${att}='([^']*)'`, 'im');
    result = content.match(re);
    if( result != null && result.length > 0 )
        return result[1];

    re = new RegExp(`\\[${tag}[^\\]]* ${att}=([^\\s]*)\\s`, 'im');
    result = content.match(re);
    if( result != null && result.length > 0 )
       return result[1];
    return false;
};

export const getInnerContent = function(tag, content, shouldAutoP=true) {
   const re = new RegExp(`\\[${tag}[^\\]]*?]([\\S\\s]*?)\\[\\/${tag}]`, 'i');
   var result = content.match(re);
   if( result == null || result.length < 1 )
      return '';

   if( shouldAutoP == true)
      result[1] = wp.autop(result[1]);

   return result[1];
};

For more details on this process, I wrote a detailed post about this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.