Now we are at the third article of the Gutenberg Custom Block Development series, in this article we are going to add some editing functionality into our block. If you haven’t read the previous article click on this link or if it’s your first time here go to our index article to check out all the articles related to this topic.
In the previous article, we have created a custom block with a heading, a paragraph, and a button. We have also learned how we can add styling into our block, but that block was static and we can’t make any changes to it. Now in this article, we are going to take a look at how we can make those heading and paragraphs editable so users can input whatever text they want to add.
Our custom block will look like the image shown above, with the customizable heading, paragraph, and button text. These texts will not just be editable but they also have some styling options like bold, italic, strikethrough accessible via the top quick action toolbar.
Now let’s see how exactly we can achieve this functionality:
Before getting into the there are few things that we need to know before making our custom block editable. Basically, we need to learn about three main things components, attributes, and props. So first understand these three and then jump to code.
In the article below we are going to use Gutenberg components to add editing capability in our custom block. So before using these components let’s understand first what these components are?
Table of Contents
Components
As we have mentioned in our previous articles via wp
package we get access to a huge library of components and some very useful functions. In this package, you will find ready-to-use components to use in your custom block, almost every type of component is inside this package. For example, in the wp.components
package, you can get components like text inputs, rich text inputs, buttons, toggles, dropdowns, checkboxes, color picker, date picker, and so on. There are also many more packages that have components that have more advanced functionalities.
How to learn more about components? Unfortunately as of writing this article, there is no complete proper documentation on components from official WordPress yet. Some documentation is available as a block editor reference guide but it’s not complete and fully detailed yet. For now, the best way to learn more about them is to check the official Gutenberg repo to check what options are available. Some of these components repo have a readme file in it that has a small sort of documentation on how to use certain components in our code. For example, you can check the readme of the button or the toggle.
But most of the time you need to check the codes to understand how things work. I know for some of you checking the codes and understanding how things work is a bit tough but you don’t need to worry, WordPress is surely working on documentation, and very soon it will be available for all of us. Till then read more about custom blocks and understand how things work then you’ll be able to understand the codes and how components work.
Some Most Common Packages
Now let’s take a quick look at some most common packages that have the most useful components that you end up using most of the time while developing Custom Blocks. In this series, we’ll try to use most of them if not all of them so you can get familiar with them as well. Whenever you want to use any components in your code you need to know in which package that component exists.
wp.components
In the wp.components
package you’ll get most of the UI input components. For example, in this package, you’ll get buttons, date picker, color picker, radio buttons, checkboxes, and so on. Additionally, this package also contents components that can be used for the block toolbar and sidebar called (InspectorControls) in the editor.
wp.editor and wp.blockEditor
These two packages are some of the most used packages. Previously when Gutenberg was new wp.editor
package was most popular and contents most of the useful components such as RichText, media uploader, and so on. But now especially after Gutenberg 5.3 release, WordPress is moving things to wp.blockEditor
and you should use wp.blockEditor
.
For now, if you use wp.editor.RichText
your code will still work but you’ll see the warning in the console that it is deprecated and use wp.blockEditor.RichText
instead. As you can see in the image above too.
wp.element
The wp.element
package contents components that are similar to React components. For example, its components are very similar to React components and fragments resemble the React Fragment. This package and its components are pretty important for custom blocks because these are the ones we use to add components like paragraphs, headings, and others to our block.
wp.i18n
This package as its name suggests wp.i18n
has functions that can be used for handling translations for any frontend text. If you have used the PHP translation function previously it contains the same function for handling translations. For example __()
and_e()
. We will learn more about this package in our upcoming articles.
Attributes
As we have mentioned before attributes are optional but one of the most important parts of the custom block. Attributes are block property that needs to be defined in key-value pair inside the registerBlockType()
function. In attributes, we need to pass attributes as an array of objects. For each attribute, the key will be its name so we can reference it inside our code, and at least the bare minimum type
property is required, or alternatively, the enum
property can also be used. Along with any one of these two some additional properties can also be added.
In type
property, we define what type of variable we are expecting it can be anything in the following; null
, boolean
, object
, array
, number
, string
, or integer
.
Example of type:
{ content: { type: 'string' } }
In enum
as you know, it is used for storing data of fixed value, with the enum
attribute we can store an array of fixed data for our custom block.
Example of enum:
{ size: { enum: [ 'large', 'medium', 'small' ] } }
For the additional properties, we can use default
and source
.
As the name suggests default
stands for any default value for our block. If the type
and source
do not match anything within the block content then the default value will be used. Also, the default property is expected to be the same as the format it expects, for example, if a type of attribute is a string then the default is expected to be a string if it is an array then the default is expected to be an array.
The source
is a bit complex because it is very powerful and useful. The source attribute is used to define how the attribute values will be extracted from saved post content.
In the source attribute, we can add the following values; (no value), attribute, text, html, query, and meta(deprecated).
The source
attribute is usually used with a selector
attribute. The selector attribute used to define from which HTML tag is should extract from. You can learn more about source and selector in the Gutenberg reference guide.
Props
Props are one of the major features of React and are used to pass variables and functions to other components. It is very important for custom blocks and is used a lot for making blocks functional. WordPress itself provides some very useful props for save
and edit
functions of register_block_types()
function. With these props, we get access to important parts of the block, such as attributes and a method to update the attributes.
Till now we are using only empty edit
and save
function but from now on we will be using them with props. Check the example below to understand better.
//Previously used edit function edit: function() { //code goes here } //Now edit function will work like this edit: function(props) { //code goes here } //Previously used save function save: function() { //code goes here } //Now savefunction will work like this save: function(props) { //code goes here }
After adding props in our edit
and save
we now have access to all the things props content. If you are curious and wanna what is in the props inside edit
and save
functions before return statement you can console.log(props);
to see the full long list of what it contains.
To access the attributes inside our save
and edit
function we have to use props. We can reference any attribute using props. To access the attribute we first use prop
prop then the attribute
keyword and then the name of the attribute prop.attribute.nameOfAttribute
.
Now we know the basics so let’s jump to use this knowledge to make our custom block editable.
Step 1: Add wp.blockEditor
Package
To add editing capabilities inside our custom block we need to use components from blockEditor
package of the wp
global package. To use these components first we need to know in which package these components exist and add that package as a dependency where we have registered our block in the plugin file.
To add it as a dependency in our plugin.php we need to add it inside wp_register_block()
function as shown in the code below, we need to add all the dependencies that we are going to use so it will be available when our block will load on the website.
wp_register_script( 'wpt-block', plugins_url( 'wpt-block/wpt-block.js', __FILE__ ), ['wp-blocks', 'wp-editor'] //dependencies );
And to use it inside our block’s JavaScrip filet(wpt-block.js) we need to parse it as a parameter in our self-invoking function. As shown in the code below.
( function( blocks, element, editor) { //code goes here })( window.wp.blocks, window.wp.element, window.wp.blockEditor); //packages as parameter
We cab reference these packages and their components via the name of parameters we have declared in the function.
Step 2: Define Attributes
The next step is to define attributes for our custom block so we can save the changes that we have made in our block. Since we want to make three things heading, paragraph, and button text to be editable we will be adding three separate attributes for each of them. See the attribute in the code below:
attributes: { textHeading: { type: 'string', default: 'Heading' }, textPara:{ type: 'string', default: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' }, textButton: { type: 'string', default: 'Click Me' }, },
Step 3: Add props
in edit
and save
Property.
The next step is to add props inside our edit
and save
property functions. We need props in our edit and save properties to access the attributes that we have declared in the above step. After adding the props in our edit and save function it will look like the code given below.
edit: function(props) { //code goes here } save: function(props) { //code goes here }
Step 4: RichText Component in edit
Now to make our custom block text editable we need to use the RichText component of the wp.blockEditor package. Since we have named it editor in our function parameter we will use editor
keyword to reference it. Now to use it we need to replace our previous h2
heading with the RichText component.
To do that in el()
we need to pass two things first RichText component second an object with the configuration of the element as shown in the code below.
el( editor.RichText, {//configuration} )
In the configuration object first, we will add tagName
, since we want a heading we will 'h2'
as a tag. Then we will add className
and as a value, we can pass our own class name or also we can pass props.className
to get default class names from props
. We can also use both using +
operator if we want. After that, we will add value
for element but we won’t use any hardcoded value here we will take value from our attributes that we added in step 2.
Now the code will look like as shown in the code below:
edit: function(props) { return( el('div', {className:'wpt-back'} , el( editor.RichText, { tagName: 'h2', className: 'wpt-heading', value: props.attributes.textHeading } ), el( 'p', {className:'wpt-para'},"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." ), el( 'a', {className:'wpt-button', href:'https://example.com'} , "Click Me" ), ) ) },
If you save the above code and add that custom block into the block editor you should be able to edit your heading tag but none of the changes you have made will be saved and on the published page, you’ll see the default value. In the next step, we will see how we can save these changes.
Step 5: Save Changes
Now to save the changes, inside the RichText configuration object after the value we need to call onChange
function to save the changes in our attributes and the attributes will save those changes inside the database, so when we reload the page we get the text we have typed. In the onChange
function, we will use the props.setAttributes()
function to save the changes in the attributes.
Now our element code will now look like the code given below:
el( editor.RichText, { tagName: 'h2', className: 'wpt-heading', value: props.attributes.textHeading, onChange: function( content ) { props.setAttributes( { textHeading: content } ); } } )
Now if you save the above code and add it inside your block editor you will be able to edit the heading and changes will be saved and if you refresh the page you’ll see the text you have typed but still, your changes won’t be visible on the published page for that we need to add the changes inside our save
function.
Step 6: Save Changes in save
Function
Now the sixth step to make our code editable we’ll need to save and show the changes in the save
function. Now to show the saved changes we also need to change the element in the save
function and use the RichText component in it.
But we can’t just use RichText
component directly because it comes with editing functionalities and saves function is just to render the block no editing it possible so we will use Content
of RichText
here. To use it we will write like pros.RichText.Content
as the first parameter and in the second parameter, we will pass configuration as an object. We will use tagName
,className
andvalue
above edit
function.
One thing to remember is we won’t use onChange
function here since save
function doesn’t expect any changes. Now our save function element will look like the code below.
save: function(props) { return( el('div', {className: 'wpt-back' } , el( editor.RichText.Content, { tagName: 'h2', className: 'wpt-heading', value: props.attributes.textHeading, } ), el( 'p', {className:'wpt-para'},"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." ), el( a', {className:'wpt-button', href:'https://example.com'} , "Click Me" ), ) ) },
Now when you save the above code and add it to the editor heading will be editable and when you save it, it will save and you will see the edited heading on the published page as well and when you get back to your page you’ll see you edited heading in the editor as well.
Since we have used the RichText component along with editing capabilities we have also unlocked some more added advanced features for our text. Now while editing in the top bar of the block you’ll see some formatting options for your editable text.
You can use the topbar formatting options to easily make your text bold, italic, link, add Inline code, add Inline image, add keyboard input, strikethrough, make text subscript or superscript and you can also change the color of text with the top toolbar without writing anything extra.
Final Step: Make Everything Editable
Now in the final step, we will make every text of our custom block editable, and doing that is pretty simple just follow the above step which we have done for heading and repeat for every element or just use the classic all-time-favorite copy&paste 🙂
After making the changes our complete code of wpt-block.js file will look like the code given below:
( function( blocks, element, editor) { var el = element.createElement; // Registering A Block blocks.registerBlockType('wpt/wpt-block', { title: 'WPT Custom Block', category: 'common', icon: 'superhero', description: 'First Hello World Block', keyword: ['test', 'searchme'], attributes: { textHeading: { type: 'string', default: 'Heading' }, textPara:{ type: 'string', default: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' }, textButton: { type: 'string', default: 'Click Me' }, }, // Block Edit Function edit: function(props) { return( el('div', {className:'wpt-back'} , el( editor.RichText, { tagName: 'h2', className: 'wpt-heading', value: props.attributes.textHeading, onChange: function( content ) { props.setAttributes( { textHeading: content } ); } } ), el( editor.RichText, { tagName: 'p', className: 'wpt-para', value: props.attributes.textPara, onChange: function( content ) { props.setAttributes( { textPara: content } ); } } ), el( editor.RichText, { tagName: 'a', className: 'wpt-button', value: props.attributes.textButton, href:'#', onChange: function( content ) { props.setAttributes( { textButton: content } ); } } ), ) ) }, //Block Save Function save: function(props) { return( el('div', {className: 'wpt-back' } , el( editor.RichText.Content, { tagName: 'h2', className: 'wpt-heading', value: props.attributes.textHeading, } ), el( editor.RichText.Content, { tagName: 'p', className: 'wpt-para', value: props.attributes.textPara, } ), el( editor.RichText.Content, { tagName: 'a', className: 'wpt-button', value: props.attributes.textButton, } ), ) ) }, } ); })( window.wp.blocks, window.wp.element, window.wp.blockEditor); //packages as parameter
And with that congratulations now you have created a block with editing capability.
Conclusion
Till now you have learned how we can make a custom block, add style in our custom block and how to make our block editable so the end-user can make changes to the block. Along the way, we learned about Gutenberg components, attributes, and props. In upcoming articles, we will take things to a more advanced level so read them as well.
You can get the complete source code used in this article and in the complete series on my Github repo.
If you have any ideas, suggestions for our questions make sure to comment them down below, and if you are confused about any step or concept related to this article put that in the comments as well we will try to respond to them ASAP.