Introduction
This summer, at Be API, we started an internal project called Blocks party , with the aim of creating a collection of Gutenberg blocks to complement the list of native WordPress blocks. These blocks will be homemade, and will of course be open-source to stay true to the WordPress DNA.
As a first step, we identified the most recurrent layouts / functionalities in our projects, from which we produced a list of candidate blocks for development. Without knowing it, I was going to start with the most difficult and complex block on the list.
I'm Paolo Tesei, a WordPress theme developer for 15 years, and below I'd like to offer you some feedback on the creation of my first native Gutenberg block.
A steep course
Everything is difficult when you start something new!
To start things off on the right foot, I used the create-block package to initialize the project, as a WordPress extension. I then added our coding standards coding for JavaScript, CSS and PHP, then switched to multi-blocks (an extension that lets you save multiple blocks at once).
Personally, I had already started to get to grips with React by developing a site using Gatsby.js. With Gutenberg, the experience is similar to developing with a JavaScript Framework: you have to adapt to its rules and way of working.
To get off to a good start, the documentation (which, to date, is not yet optimal) remains the first piece of the puzzle, although there aren't many examples yet. To make up for this lack, since everything is open-source, it's easier to find and take a look at how other developers have used it (and whether or not they've also fallen into the same traps as me).
The origin of evil
The first block the project team decided to develop was the "Tabs" block. Highly requested/used in our projects, this block consists of a tab bar (tabs list) and content panels (panels), with the added bonus of allowing the user to choose an icon for each tab.
As we'd already developed an "Icons" block for loading icon collections, I preferred to exploit theinnerBlocks system (nested blocks) to respect the concept of modularity and functional independence, rather than transforming this block into a component.
The "Tabs" block
After a few days spent trying to design this block from a single children's block, I finally realized that no less than 4 were needed to make the block in the most logical and coherent way!
To be more precise, in this "Tabs" block, we find the first two level 1 blocks, one containing all the tabs (tabs list) and another containing all the panels (panels). The children (level 2) of the latter are synchronized, which means that if I move the first tab(tab item) to the second position, the corresponding content (panel item) will follow and be positioned in the same order in the list of panels.
In this phase, the hardest part was figuring out how to make the blocks talk to each other. Basically, in Gutenberg, each block lives its own life, but there are several solutions to enable these blocks to interact. Of course, I had to try each of these methods to determine which would work best. So I used contexts (the Gutenberg equivalent of Redux) and Select and Dispatch to retrieve data from the block register. Another option was to create a dedicated Store, but this was clearly an over-dimensioned solution, so it was quickly abandoned.
Small constraint (and tip): throughout the development phase, the block is often broken (as many times as the development logic is changed) and regular recontribution is required to make it (re)work. The message "This block has encountered an error and cannot be previewed" becomes your best friend. As the message is not very explicit, it's not easy to understand where the error comes from. I therefore advise you to develop little by little and test continuously to avoid the frustration of making too many changes!
While in most cases the error is due to a markup change, this feature (no, no, it's not a bug) highlights the fragility of blocks. So it's important to bear in mind that if you're upgrading your block in the future, you'll need to take backward compatibility into account.
We started by establishing (for this block, but for the following ones too) general naming rules for prefixing our blocks, CSS classes and variables and the namespace of our plugins.
To make the whole thing more flexible and developer-friendly, we've made it possible to parameterize which types of block we can add insidetabs andpanels, with a list ofallowed blocks.
Overall, we need to think about how to make each block flexible and open enough to interact with the other extensions/blocks in the ecosystem.
At the same time, you need to ensure that the interface is effectively restricted , to offer less experienced contributors only those options that will be useful to them, or simply to adapt block editing to a well-defined artistic direction.
For the "Tabs" block, I've disabled the editing of certain elements(locking) to avoid contribution errors, and I've also made it possible to limit and customize the list of possible alignments.
By modifying the blockSupport configuration, it is also possible to enable or disable the display of native options such as the color picker or margin management.
A final source of reflection concerns CSS. In preparation for the massive arrival of FSE (Full Site Editing, rather Site editor( recentrenaming )), we need to identify the style parameters that allow us to edit the visual aspect of the block, and then create the associated CSS variables.
The three rules
In the classical theater of 1500, inspired by Aristotle, the perfect play had to be conceived according to the following three rules:
- unity of time: everything must take place within one day;
- unity of location: everything must take place in the same place/space;
- unity of action: all the main events in the story must begin and end within the room.
I found it quite amusing to be able to apply these "Aristotelian units" to the development of Gutenberg blocks.
Time unit.
The life of a block stretches from an editing phase(edit) to a saving phase(save), and these two phases are intimately interconnected. It's essential to make the editing interface faithful to the front-office rendering. This is particularly true when developing a block that is not rendered dynamically. The markup of its save part also dictates the structure of its edit.
Unity of location
This concept is important for modularity: when not all functionalities can be carried by a single block, we are forced to break it down into a parent > child structure. This rule is imposed by the fact that in a Gutenberg block, we are allowed to use a single innerBlock. For example, the native "Buttons" block (an innerBlock wrapper) is the parent of the native "Button" block.
Unit of action
All manipulations modify block attributes simultaneously. We must therefore try to favour a certain order of interaction to ensure the most logical and natural contribution possible:
- in page content(editor)
- in thetoolbar to access these main settings
- in thesidebar, where you'll find its more advanced options.
Conclusion
Even if the initial set-up was a little complicated, I had a lot of fun creating this block.
A closer look at thecore blocks of WordPress made me realize the care and thought that goes into each block, as well as the quantity and quality of work that goes into Project Gutenberg.
For everything I've learned/discovered, hats off to you and thanks to the community!