How to convert WordPress Shortcodes into Blocks

·

·

In this tutorial I’m going to show you how to create a basic block which mimics the functionality of an existing shortcode but providing a much better user experience.

We’ll demonstrate the case when there is already an existing plugin where we want to progressively migrate existing shortcodes into new blocks. Here you’ll find the GitHub repo with all the code.

Creating the Message Shortcode

We are going to start with a shortcode that displays a message with a couple of attributes: text and color :

Here is the plugin file including the shortcode:

<?php
/**
 * Plugin Name: Shortcode to Block
 */

if (!defined('ABSPATH')) {
    exit;
}

add_shortcode('message', function ($attributes) {
    $atts = shortcode_atts(array(
        'color' => 'red',
        'text' => 'Default text goes here...',
    ), $attributes);

    return sprintf(
        '<p style="color:%s;">%s</p>',
        esc_attr($atts['color']),
        esc_attr($atts['text'])
    );
});

Creating the Message Block boilerplate

We are going to use @wordpress/create-block package to create the block boilerplate, in the root of your plugin run the following command:

npx @wordpress/create-block@latest message --no-plugin

Notice --no-plugin parameter at the end to not include the plugin file, omit this parameter if you want to create it from scratch.

If you are creating the plugin from scratch (using the above command without --no-plugin parameter), feel free to skip the following section as @wordpress/scripts package is going to be installed and configured automatically for you.

The above command creates a message directory with all the files needed for the block:

Next thing to do is install @wordpress/scripts package to build the assets, to do so run the following command:

npm install -D @wordpress/scripts

Once installed add the following scripts to your package.json:

  "scripts": {
    "build": "wp-scripts build --webpack-src-dir=message",
    "start": "wp-scripts start --webpack-src-dir=message"
  },

Notice how we are adding --webpack-src-dir parameter to indicate the source directory, in this case our message directory.

Now run the following command to build the assets:

npm run build

The above command compiles all the assets into a new build directory in the root of the plugin:

Finally we need to register the block, to do so add the following code to your plugin file:

add_action('init', function() {
    register_block_type( __DIR__ . '/build' );
});

At this point we are ready to start working on the Message Block, let’s add it to our post:

Adding Block Attributes

The first thing to do is adding attributes to the Block, in our case only the text attribute as we are going to handle the color through the Block UI. Add the following to block.json:

  "attributes": {
    "text": {
      "type": "string",
      "default": "Default text goes here..."
    }
  },

In order to see the changes while developing please run the follow to command to watch and compile on each change:

npm run start

Then open edit.js and replace the Edit function with the following:

export default function Edit({attributes, setAttributes}) {
    const {text} = attributes;

    return (
        <TextControl
            {...useBlockProps()}
            label="Text"
            value={text}
            onChange={(value) => setAttributes({text: value})}
        />
    );
}

Here we are getting the text attribute from block attributes and adding its value to a TextControl component. We are also implementing the onChange by setting the value through setAttributes.

In order to see the text value reflected in the frontend we have to include it in save.js file like so:

export default function save({attributes}) {
	const { text } = attributes;

	return (
		<p { ...useBlockProps.save() }>
			{ text }
		</p>
	);
}

If we reload the editor page now we’ll see the default value we added into block.json also we can update and save the value that is going to be displayed in the frontend:

Using Supports for Block Styling

Here is where we are going to notice a user experience improvement compared to how we handled color attribute in the shortcode.

For basic block style we can include features into Supports, in our case we are going to include color like so in our block.json file:

  "supports": {
    "color": {}
  },

By adding the above we have now a complete UI for handling color in our block.

As we are going to get the styles from the block now please delete the contents of style.scss and editor.scss so we can clearly see how styles are applied.

That’s all, we have now created a block from an existing shortcode, while basic it demonstrates the steps to follow when we want to migrate existing shortcodes into new blocks.