Converting a Shortcode into a Block

In this tutorial, you’re going to learn how to convert an existing WordPress shortcode into a block. We’ll be using the scaffolded code created by the Create Block tool, and applying it to an existing PHP-only plugin.


  • Introduction: 0:00 – 0:49
  • Shortcode review: 0:49 – 2:00
  • Setting up the plugin for block development: 2:00 – 6:15
  • Registering the block type in PHP: 6:15 – 8:20
  • Creating the block source code and running the first build: 8:20 – 12:05
  • Creating the Edit component and save function: 12:05 – 16:30

Learning outcomes

  1. Set up an existing plugin for block development
  2. Create the necessary source files to develop a new block
  3. Register the block type in the plugin
  4. Create the Edit Component
  5. Create the save function
  6. Add the newly created block in the editor, and view it on the front end

Comprehension questions

  1. What is the command run to create the package.json file?
  2. What is the name of the file that contains the block metadata?
  3. What command is run during development to watch the source files, and run the build step if anything changes?
  4. What React hook is used in the Edit component to pass block properties to the component?


Hey there, and welcome to Learn WordPress.

In this tutorial, you’re going to learn how to convert an existing WordPress shortcode into a block. We’ll be using the scaffolded code created by the Create Block tool and applying it to an existing PHP-only shortcode plugin. If you don’t know what the Create Block tool is, I recommend watching the tutorial on using Create Block first and then coming back here. In this video, we will cover preparing an existing shortcode plugin for block support, setting up the block registration in PHP, working with the blocks Edit component to render the block in the editor, and working with the block save function to save the block output on a post or page.

Suppose you have a plugin which adds a new shortcode called wp-subscribe. The shortcode can be added to a post or page in WordPress. When you view the post or page the shortcode renders its HTML output, which includes some text and a clickable link to subscribe page.

If we inspect the HTML that the shortcode renders this is what it looks like. It has a div with a custom class, outputs Subscribe in a h2 tag, the content in the paragraph, and the link to the subscribe page. Your plugin code might look something like this; adding the shortcode function and rendering the content. You would now like to convert the shortcode into a block so that anyone who installs this plugin can add a subscribe block in the Block Editor. Given what you’ve learned by creating a new block with the Create Block tool, you can start adding the required pieces to your existing plugin.

Your first step is to prepare the plugin. You will need to create a new package.json file for your existing plugin which manages the necessary dependencies and the different npm scripts. Open your terminal and switch to the plugin folder. In my case, it’s in development/websites/wordpress/wp-content/plugins/wp-learn-subscribe.

Then run the following command:

npm init 

The command will ask you a series of questions which will be used to create your package.json file. You can accept most of the defaults except the license which you will need to specify as GPL 2.0 or later. This is to match the WordPress GPL license requirements.

Accept, accept, I’ll leave that empty. I’ll leave that empty, I don’t need a test command. I’ll leave the repository as it is, I don’t need keywords, pop my name, oops can’t spell, my name in as the author, and then update the license, 2.0 or later.

The final output on your screen should look something like this. The npm init process will make different suggestions depending on the original source code and whether you’re using version control for your project or not. Depending on how you responded to your questions, your final package json will be created and should look something like this. There we go.

Your next step is to install the WordPress scripts package. This is what is used to create the final block assets in the build directory of your plugin. From the same terminal window, run the following command:

npm install @wordpress/scripts --save-dev 

The –save-dev option tells npm to install these as a dev dependency. This can take a while. Once this is done, you need to make two changes to your package.json file. First, browse to the Block Editor handbook and navigate to the Reference guides, Package reference, WordPress scripts

Copy the scripts from the setup section and overwrite the existing scripts section in your package.json file to override this test script.

Fix that bug.

Next, update the main field in your package.json to point to the index file in the build directory. This directory or file doesn’t exist yet, but it will be created the first time we build the block code. All we need to do is update this to point to build. Your final package.json should look something like this. The main field has been updated, the scripts have been added and wordpress/scripts is specified in the dev dependencies field.

If you take a look at your project folder, you will also see a new node_modules directory which contains all the required dependencies that were installed.

Before you can start writing any JavaScript code, you first need to register the block type for the Block Editor. This is done in PHP using the register_block_type_function. You can read more about this function in the WordPress developers function reference.

Search register block type and register your custom block type by using the following code in your main plugin file.

So we’ll start by adding an action, binding it on the init action hook. And we’ll go wpl, wpl_subscribe_block_init and then we can copy that function name and register the function. It doesn’t need any parameters. And then we say register_block_type and we pass in the DIR constant, which is the directory of the current file, and we concatenate that with the path to the build directory.

This hooks the wpl_subscribe_block_init function to the WordPress init hook and calls the register_block_type function to register the block. As with the main field in the package.json file, the path to the build directory you’re passing to the register_block_type function doesn’t exist yet, but it will be created the first time we build our block.

Now you can start building your block source code by creating the src directory in your plugin folder, and then creating all the relevant files, the index.js file, edit.js, save.js, etc. You could manually create these files but for your first block it will save you some time if you copy those files from an existing plugin created by the Create block tool and edit them to suit your current shortcode functionality.

So in this example, I’ve already got the learn-to-do. So I’m going to grab the src folder and copy it over to my new plugin. The first file you need to edit is the block.json file. This file specifies all the properties of your block.

For now you will just need to change the following fields at a minimum; the Name field – this must follow the namespace/block-name format, where the namespace is the unique name of your plugin also known as the plugin slug. wp-learn-subscribe and then we could just say wp-learn-subscribe-block

The title: the block title that appears in the block list when the user wants to add a block. Update this to wp-learn-subscribe.

The description: a description for your block. So let’s say Add a simple subscribe block, and then the text domain which is used for translating any strings in your block. This is usually the same as your plugin slug. Grab the slug and update the text domain.

You can read about the other block.json fields in the Block Editor handbook documentation under Reference Guides, Block API Reference, Metadata in block.json, but for now, the current values will suffice. You’ll notice this file also specifies a path to the editor style and style files. But your block has no styling at the moment. Look out for the Styling your block enabled plugin tutorial and how to use these files to style your block.

While you’re developing your block, you will need to run the npm run build command every time you want the code in your source directory to be transpiled into the final block assets in the build directory. During the development process, you can use the WordPress scripts development server, which is built on top of webpack to keep watching the files in your source directory for changes and update the build directory. To do this, switch back to your terminal and run the following command:

npm start.

Make sure this is inside the plugin directory. The development server will build all the block assets in the build directory and then watch as the source directory for any changes. If a change is made, it rebuilds all the block assets. The output looks something like this. And if you switch back to your plugin, you can see the build directory has been created. You can monitor npm start output during development and if it reports any errors something is wrong with your code.

The next two files to update are the edit.js and save.js files also known as the Edit component and the save function. It’s a good idea to edit these two at the same time, as they will determine the block functionality in the editor. The Edit component is the code that is run whenever you add or edit a block in the editor and returns the output of the block. With more complex blocks, the Edit component also handles things like block controls, block settings and user inputs. But for this example, it only needs to return the block output. If you scroll to the bottom of the Edit component, you see the component returns the output from the scaffolded block. The output being returned here uses a special format called JSX, which is very similar to HTML. You need to update this so that it matches the code being returned in the original wp-subscribe shortcode. To simplify this, copy the HTML rendered by your shortcode and convert it into the JSX format. When creating your first JSX code, it’s often less difficult to copy the final HTML into the block and then convert it rather than trying to convert the PHP code which may have a bunch of PHP open close tags and echo statements.

So first of all, grab the HTML and we’ll pop it in just below the existing code. To convert this into JSX code that can be returned by your block, you need to make one change. Convert the container div to use the useBlockProps in place of the custom class set.

Take that, pop it in there that this out the way then just do some formatting.

Note the use of the curly braces around useBlockProps. This is similar to the PHP opening and closing tags and indicates a JavaScript expression that needs to be processed. useBlockProps is a special React hook that will apply any necessary properties to the block wrapper element. You’ll see what this does later on. Next, you can also edit the save function in a similar fashion. The save function determines how the block output is going to be stored in the database. Again, because we’re not doing anything complex, it just needs to return the block output. The original return looks like this. And then we copy over our updated code for save.

The main difference here is using in the container div tag, which is required for the save function. If you switch back to your terminal and scroll up, you should see that the build process failed with some errors but then successfully built the assets after editing the save function. If you add this block to a post, you will see how it creates the block and renders the HTML.

So let’s go back to different post, let’s add a new block and there’s learn subscribe. And there’s our block.

If we update this and view it on the front end, there’s our block content.

Congratulations, you’ve successfully created a block from an existing shortcode. For more tutorials on Block Development, look out for the styling your block enabled plugin and using block attributes to enable user editing tutorials on Learn WordPress.

Happy coding!

Additional Resources

Workshop Details


Jonathan Bossenger

WordPress Developer Educator at Automattic, full-time sponsored member of the training team creating educational content for developers on Learn WordPress. Husband and father of two energetic boys.