In this post I will show you how I was able to start creating WordPress block plugins.
I am still in the beginning stages of learning this myself. As I go through the documentation and develop working examples, I will post the examples with problematic issues I faced that could help others. There is a lot of documentation out there but it isn't very clear in some cases. Good information is also available on Stackoverflow but they seem to be more advanced issues with established templates.
I started my attempt to create a very simple block plugin for another website. It was suppose to be a quick day project that easily turned into a few days due to my specific struggles in going from beginner coding attempts to a more advanced attempt. I quickly had to rewind to learn the basics before I could move forward. This is what the post below is about. I want to inform about the basics and how WordPress handles the edited data when creating blocks in your posts. Some parts I skimmed over are covered well in the WordPress development documentation and I focus on the parts that I struggled with.
I am demonstrating this in a development environment on a Windows machine with WordPress installed in IIS. The actual project example is far from a complete block plugin. I am posting this because I have just been able to differentiate the necessary components needed between the two types of rendering. I wanted to share while it was fresh.
Creating WordPress Block Plugins
Use the link below to view a guide I created on how to install WordPress on IIS.
Types of Block Rendering
WordPress has two main types of block rendering. There are treated differently based on the supplied data.
Static
Static rendering is when you supply a data set used to create the front end markup for the site elements. These are attributes that are created when building the block plugin. The data in the attributes can change but the attributes types can not change. The data is not dynamically created from outside sources. In the example I post below, I am changing the text of a paragraph element.
Dynamic
Dynamic render is used when you have a potentially ever changing set of data used to create the front end markup for the site elements. An example would be getting the data from the last 5 posts to use in your plugin. As you publish more posts, the last 5 posts could change. In the example I post below, I use an empty array. When the user builds their post with the custom block plugin, they can edit it. The dynamic part is that the array could change in size, 1 element or 15 elements each with different values.Â
Setup
You will need to setup Node.js development tools on your system in order to create WordPress block plugins.
I will post two links below that you can use as a guide to install the Node.js developments tool.
Create and Setup React App For Android - this is a previous post of mine. The beginning steps are the important steps for this guide. They show you how to add React.js to your system.
Once your system is setup to work with Node.js, we can now start creating WordPress block plugins.
WordPress Tutorial: Build your first block should be your starting steps. They walk you through the beginning parts well. I want to add in the information that doesn't seem clear and took me some time to figure out. This guide will have you import a sample project template to use as a foundation to creating WordPress block plugins.
I am starting after you import the template project they specify from the link above to use with the following command.
Navigate to your WordPress plugins folder. Here you have two options.
Option #1
You can have a guided build with options that populate for you to customize by executing:
npx @wordpress/create-block@latest
Option #2
Or you can have a project template created with the project name of Copyright Date Block built by executing:
npx @wordpress/create-block@latest copyright-date-block --variant=dynamic
cd copyright-date-block
Open a code editor in the src/<plugin_name> directory to display the necessary files needed to edit.
IMPORTANT
npm run start
Static Rendering Block Plugin
block.json
The attributes and the support parts are where we will spend some time. The rest is explained well enough in the WordPress Developer Documentation site.
Attributes
The attributes value is an array of values used to create/build the block plugin. These values could be what is used on the front end for the user to change, such as a title for something or padding for DOM elements created while customizing the plugin. Attributes for each item will need to have a few things specified.
Support
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "create-block/copyright-date-block",
"version": "0.1.0",
"title": "Copyright Date Block",
"category": "widgets",
"description": "My new description here...",
"example": {},
"attributes": {
"rowCount": {
"type": "number",
"default": 2
},
"staticElement": {
"type": "string",
"default":"",
"selector":"p"
}
},
"supports": {
"color": {
"background": true,
"text": true
},
"html": true,
"typography": {
"fontSize": true
}
},
"textdomain": "copyright-date-block",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js"
}
index.js
This is mostly taken straight from the template. The only changes here are for the save functions.
/**
* Registers a new block provided a unique name and an object defining its behavior.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
import { registerBlockType } from '@wordpress/blocks';
/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* All files containing `style` keyword are bundled together. The code used
* gets applied both to the front of your site and to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
import './style.scss';
/**
* Internal dependencies
*/
import Edit from './edit';
import save from './save';
import metadata from './block.json';
/**
* Every block starts by registering a new block type definition.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
registerBlockType( metadata.name, {
/**
* @see ./edit.js
*/
edit: Edit,
/**
* @see ./save.js
*/
save,
} );
Added the following two lines.
These will enable you to save data changes to your WordPress database in HTML block coding syntax.
import save from './save';
    /**
       * @see ./save.js
    */   Â
    save,
Save.js
This will just need to be created. In the beginning of the guide from WordPress using this template, it is not there. Later steps in the guide, they have you create it.
There are a few important notes here. The RichText utilized here will need to be RichText.Content otherwise you will get an error. The tagName has to be the same as the selector you chose in the block.json.
The structure for the Edit.js and Save.js need to be the same or the plugin will fail. WordPress checks the compiled HTML code with the code saved in the database to ensure they are the same. If they differ, it will fail to load. That is why this is considered static rendering. The Save.js has no setAttributes method to use in altering the data.
import { __ } from '@wordpress/i18n';
import { useBlockProps, RichText } from '@wordpress/block-editor';
export default function save( { attributes } ) {
const blockProps = useBlockProps.save();
const { staticElement } = attributes;
return (
<>
<div { ...blockProps }>
<RichText.Content
className= { "blah_" }
tagName="p"
value={ staticElement }
/>
</div>
</>
);
}
Dynamic Rendering Block Plugin
To create a dynamic block plugin, I will be using an array attribute. The array attribute will be created in edit mode with any number of text elements to be displayed as a DOM p.
Block.json
There are only a few changes here. I updated the attributes to add in an array named "content"Â .
On the bottom, I added in a render parameter to include a new file named render.php. This is how you will be able to display the dynamically created array of elements in WordPress.
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "create-block/copyright-date-block",
"version": "0.1.0",
"title": "Copyright Date Block",
"category": "widgets",
"description": "My new description here...",
"example": {},
"attributes": {
"rowCount": {
"type": "number",
"default": 2
},
"content": {
"type": "array",
"default":["",""],
"selector":"p"
},
"staticElement": {
"type": "string",
"default":"",
"selector":"p"
}
},
"supports": {
"color": {
"background": true,
"text": true
},
"html": true,
"typography": {
"fontSize": true
}
},
"textdomain": "copyright-date-block",
"editorScript": "file:./index.js",
"render": "file:./render.php",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js"
}
Index.js
Nothing in here has changed. We will make the necessary change in save.js.
/**
* Registers a new block provided a unique name and an object defining its behavior.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
import { registerBlockType } from '@wordpress/blocks';
/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* All files containing `style` keyword are bundled together. The code used
* gets applied both to the front of your site and to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
import './style.scss';
/**
* Internal dependencies
*/
import Edit from './edit';
import save from './save';
import metadata from './block.json';
/**
* Every block starts by registering a new block type definition.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
registerBlockType( metadata.name, {
/**
* @see ./edit.js
*/
edit: Edit,
/**
* @see ./save.js
*/
save,
} );
Save.js
Basically we are just returning null. This will bypass the save.js to validate and pull the saved HTML from database. WordPress will use the render.php for the front end creation.
import { __ } from '@wordpress/i18n';
import { useBlockProps, RichText } from '@wordpress/block-editor';
export default function save( { attributes } ) {
return null;
}
Render.php
Dynamic rendering is taken place here. This is where the HTML on the front end is created from the saved attributes in the database.
<?php
/**
* @see https://github.com/WordPress/gutenberg/blob/trunk/docs/reference-guides/block-api/block-metadata.md#render
*/
$rowCount = $attributes['rowCount'];
$c = $attributes['content'];
?>
<div <?php echo get_block_wrapper_attributes(); ?>>
<p><?php esc_html_e( 'Copyright Date Block – hello from a dynamic block!', 'copyright-date-block' ); ?></p>
<?php
foreach($c as $text){
?>
<p class="example">
<?php echo esc_html( $text ); ?>
<?php
}
?>
</p>
</div>
Edit.js
This part took me awhile primarily due to the syntax rules in Javascript and how React works. I need to brush off some cob webs from my Javascript.
The flow is:
/**
* Retrieves the translation of text.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-i18n/
*/
import { __ } from '@wordpress/i18n';
/**
* React hook that is used to mark the block wrapper element.
* It provides all the necessary props like the class name.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops
*/
import { useBlockProps } from '@wordpress/block-editor';
/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* Those files can contain any CSS code that gets applied to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
import './editor.scss';
/**
* The edit function describes the structure of your block in the context of the
* editor. This represents what the editor will render when the block is used.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#edit
*
* @return {Element} Element to render.
*/
import { InspectorControls, RichText } from '@wordpress/block-editor';
import { PanelBody, TextControl } from '@wordpress/components';
import { __experimentalNumberControl as NumberControl } from '@wordpress/components';
export default function Edit( { attributes, setAttributes } ) {
const { rowCount, content } = attributes;
const blockProps = useBlockProps();
function updateArray(arr, attributes){
if(arr < 0){
//return if accidently set invalid number
setAttributes({rowCount : 0});
return;
}
if(arr === ""){
//return is no value entered
return;
}
{blockProps}
console.log(arr + " - " + attributes.rowCount);
var oldArr = attributes.content;
//check whether new input is bigger or less then do action on array
if(arr > attributes.content.length){
var diff = arr - attributes.content.length;
for(let i = 0; i < parseInt(diff); i++){
oldArr.push("");
}
setAttributes({ content: oldArr });
} else if(arr < attributes.content.length) {
var diff = attributes.content.length - arr;
setAttributes({ content: oldArr.slice(0, -diff) });
}
//update the row number
setAttributes({rowCount : arr});
}
function updateText(index, text, attributes){
{blockProps}
console.log(index + " = " + text);
var oldArr = attributes.content;
oldArr[index] = text;
setAttributes( { content: oldArr });
}
return (
<>
<InspectorControls>
<PanelBody title={ __( 'Settings', 'copyright-date-block' ) }>
<NumberControl
__next40pxDefaultSize
spinControls='native'
label = { __('Configure row count')}
isShiftStepEnabled={ true }
onChange={ ( value ) =>
updateArray(value, attributes) }
shiftStep={ 1 }
value={ parseInt(rowCount) }
/>
</PanelBody>
</InspectorControls>
<div { ...blockProps }>
{ content.map((item, index) => {
return (
<RichText
className= { "blah_" + index }
tagName="p"
value={ item }
allowedFormats={ [ 'core/bold', 'core/italic' ] }
onChange={ ( value ) => updateText(index, value, attributes) }
placeholder={ __( '?...' ) }
/>
)
})
}
</div>
</>
);
}