We’re all well aware that the new WordPress editor is driven by React to create interactive and reusable blocks to deliver a rich experience for users. While it’s likely that the Block API will lessen the frequency of use of the Shortcode API, the two can and do interact well. In this tutorial, we’ll create something of a shortcode that is wrapped up as a block and deliver dynamic data from the server to the browser.
Since this tutorial intends to illustrate the interaction of javascript with php, I’ve created a companion repository with a plugin that you can download to a local installation of WordPress 5.0x. Running this code locally will allow you to make changes and switch branches to compare the effects of code changes to what and how things render in the browser.
Start with Javascript
As with any block, we need to use javascript to register a block. To have the block show up in the list of blocks, we will need something like this:
registerBlockType( 'pbrocks-exploring/pbrocks-block', {
title: 'PBrocks Block',
icon: {
background: '#29c8aa',
foreground: '#ffffff',
src: 'megaphone',
},
category: 'common',
edit: function( props ) {
return []
},
save: function() {
return;
},
} );
To start, you’ll want to pull the repository, navigate to the plugin folder, run npm install
and npm run dev
, as well as activated the plugin.
Looking at the code we see that we are creating a block called PBrocks Block and we should be able to find this block under the Common section of the block inserter. To make the block selection more salient, the icon will have a seafoam green background.

Assuming that you are viewing the Master branch of the repository, when you select the block, what gets inserted into the editor should look like this:

For the purposes of illustrating how the dynamic nature works, the block contains three lines of text that are distinct from one another and an area in the sidebar where the text of the editor can be changed. When building a block for production, you would mostly like want your user to edit text directly in the editor window.
Publishing your page and viewing on the frontend will display the first line wrapped in an H2, the second an H4, and the third a P tag. How this block differs from most others is that the html is delivered by PHP.
Support from PHP
Although your theme will affect the presentation on the frontend, our PHP code inserts the html elements for each and also changes the color of the first element. While this isn’t the most user-friendly way to deliver content to the browser, we’re doing so to emphasize the intersection of shortcodes and blocks. You’ll recall that we register blocks in javascript, but when we want to marry the power of javascript with php, we replicate the function signature in the php code.
register_block_type(
'pbrocks-exploring/pbrocks-block',
array(
// The script name we gave in the wp_register_script() call.
'editor_script' => 'pbrocks-exploring',
'render_callback' => 'pbrocks_block_render',
)
);
The code above is the portion that ties the PHP into our block, but this bit alone will throw an error because it calls for a callback to render the block. In that render_callback
we create the code that corresponds to a shortcode. The callback looks like this:
function pbrocks_block_render( $attributes ) {
$return = '<h2 style="color:salmon;">' . ( print_r( $attributes['value_one'], true ) ?: 'value_one not defined' ) . '</h2>';
$return .= '<h4>' . print_r( $attributes['value_two'], true ) . '</h4>';
$return .= '<p>' . print_r( $attributes['value_three'], true ) . '</p>';
return $return;
}
Excusing the inelegance of the PHP, we see for each input area of the editor sidebar, we are concatenating the three and spitting out the code for each wrapped in its respective HTML. The result of this function is that we are gathering the information for the database, wrapping it in some HTML, and then returning the parcel as a manageable unit in JSON.
As a Shortcode
In case you were wondering, this callback function will operate as a shortcode because we define that action in the initialization function.
add_shortcode( 'pbrocks-exploring-shortcode', 'pbrocks_block_render' );
Using the familiar action from the Shortcode API, we assign the shortcode tag to the same function as the render_callback
parameter. By doing this we can use the shortcode tag in its own block, and after assigning values to the defined attributes we wind up the same result on the frontend as if we had done so in the editor.

In previous versions of WordPress, the editor wasn’t as discerning as the new block-based editor, and shortcodes that contained raw html or echoed php could still render in both the editor and the frontend. Since we now need to package the php output in json for javascript, that strategy won’t work. In a branch of the repository, I give an example of code that will fail validation and discuss below.
Attributes
In the comments of block.js
I mention where attributes are typically lined up, but since we are using PHP to deliver our content, we are doing this in PHP. In fact, you may have noticed that the input to the render function above takes the attributes as its argument. In this case, the attributes are added to the initialization function as an optional parameter of the array.
register_block_type(
'pbrocks-exploring/pbrocks-block',
array(
'attributes' =>
array(
'value_one' => array(
'type' => 'string',
'default' => 'A simple text box',
),
'value_two' => array(
'type' => 'string',
'default' => 'Ain\'t this purdy?',
),
'value_three' => array(
'type' => 'string',
'default' => 'This will be more of a description.... And I could go on and on...',
),
),
// The script name we gave in the wp_register_script() call.
'editor_script' => 'pbrocks-exploring',
'render_callback' => 'pbrocks_block_render',
)
);
The three strings defined in the attributes above are sent to the editor as strings with their respective default values via JSON. If changes are made in the editor, the PHP will receive the changed JSON and update the content delivered to the browser.
Step One Branch
Scaled back to one argument, a text input that is edited and displayed in the editor.

Step Two Branch
One argument with display in the editor, but content is editable in the sidebar.

Step Three Branch
Three arguments again (mirroring Master) editable in the sidebar.

Won’t Work Branch
WordPress 5.0x and its new editor is more particular with the content delivered from PHP to the editor. The content gathered in a function needs to be returned, so that it can be packaged into valid JSON. Echoing that content, whether in PHP or raw HTML, cannot be squeezed into a JSON object.
This is ok
function pbrocks_block_render( $attributes ) {
$return = '<h2 style="color:salmon;">' . ( print_r( $attributes['value_one'], true ) ?: 'value_one not defined' ) . '</h2>';
$return .= '<h4>' . print_r( $attributes['value_two'], true ) . '</h4>';
$return .= '<p>' . print_r( $attributes['value_three'], true ) . '</p>';
return $return;
}
This is NOT ok
function pbrocks_block_render( $attributes ) {
echo '<h2 style="color:salmon;">' . $attributes['value_one'] . '</h2>';
echo '<h4>' . $attributes['value_two'] . '</h4>';
echo '<p>' . $attributes['value_three'] . '</p>';
}
Rather than returning PHP in the render function, the render attempts to echo something, which might work as a shortcode. As a block, the same render likely will display on your published post, but it will cause an error in your editor.

With the patterns above, you can begin to define which shortcodes in your theme or plugin would benefit most by being rendered as a block.