The simplest custom block is a "pure layout" block. This means we're defining a specific, nested layout of other blocks. With a bare minimum of code-writing, and no knowledge about how Gutenberg works, you can already create this type of block.
Everyone uses layouts in web development -- patterns that we want to repeat, even if just a few times. In React, we typically create a component for that, maybe calling it a "molecule" or "organism."
That's what we're doing in Atlas too, except it will be a block that appears in Gutenberg, that is WYSIWYG, and that gives the front-end developer fine-tuned control over what the Gutenberg author is allowed to do.
Let's define a layout called "Feature." This will be a column that includes an icon, a title, and a description of a feature in a product. We want to be able to create a "Feature" as a single block in Gutenberg.
Every custom block in Atlas is a directory containing a few files with specific names. You can put these directories anywhere; for simplicity, we'll assume there's a directory called blocks
off the root of the project.
Start by creating the following files (notice the file extensions!):
/blocks/ feature/ editor. js /blocks/ feature/ meta. ts /blocks/ feature/ index. ts
For complex custom blocks, with their own properties, custom Gutenberg editors, custom React components, and custom SCSS, you will use all of these files. For layouts, however, we have shortcuts where we can ignore all that.
editor.js
defines the Gutenberg editor. The entire file can be just the following, using an Atlas short-cut utility that works for any pure-layout block:
export {PureLayoutEditor as default } from 'gutenberg'
index.ts
defines the React component. Again the entire file can be just the following, using an Atlas short-cut utility, and including something from meta.ts
which we'll implement next:
import {registerPureLayoutSuperblock } from '@asmartbear/ gutenberg- bridge/ dist/ react- util'; registerPureLayoutSuperblock(require('./meta').default);
Now for the real work! in meta.ts
we define the "meta-data" for the custom block. This includes all the information needed for Gutenberg, for Storybook, for React, as well as for the layout of blocks. Here'e the complete implementation, followed by an explaination:
import { Props,SuperBlockMeta, makeLayout } from '@asmartbear/ gutenberg- bridge/ dist/ types'; importiconDefinition from '@asmartbear/ gutenberg- bridge/ dist/ blocks/ atlas- material/ icon/ meta'; importboxDefinition from '@asmartbear/ gutenberg- bridge/ dist/ blocks/ atlas/ box/ meta'; importproseDefinition from '@asmartbear/ gutenberg- bridge/ dist/ blocks/ atlas/ prose/ meta'; const definition:SuperBlockMeta<Props> = { uiType: 'tutorial/feature', blockMeta: { title: "Feature", description: "An icon, title, and description of a product feature", },propsMeta: { },gutenbergMeta: { dashicon: "layout", category: "tutorial", },layout: [makeLayout({atlasId: "outer", block: boxDefinition, props: { maxWidth: "375px" }, children: [ makeLayout({ atlasId: "icon- container", block: boxDefinition, props: { alignH: "center", marginBottom: 1 }, children: [ makeLayout({ atlasId: "icon", block: iconDefinition, props: { color: "primary", sizePx: 16 * 4, backgroundVariant: "circle" }, allowChange: ["icon"], }), ] }), makeLayout({ atlasId: "headline", block: proseDefinition, props: { backgroundColor: "backdrop", textSize: 130, placeholder: "An incredible feature", align: "center", whiteSpace: "nowrap" }, allowChange: ["content"], }), makeLayout({ atlasId: "explain", block: proseDefinition, props: { backgroundColor: "backdrop", textSize: 100, align: "center", placeholder: "A full description of the benefits of this feature. " }, allowChange: ["content"], }), ], }),],};export default definition;
Let's unpack everything:
uiType: 'tutorial/ feature'
blockMeta
propsMeta
gutenbergMeta: { dashIcon: . . . }
dashicon
assigns a standard WordPress icon to the block, for display in the block-insertion UI. Here is the list of choices. Grab the name by looking near the top of that page, ignoring the "dashicons-
" prefix.gutenbergMeta: { category: . . . }
layout
makeLayout()
utility. Most of the contents are self-documenting -- the block's definition, any properties (all optional), and optionally a list of children. The other fields we'll describe next.makeLayout( { atlasId: . . . })
makeLayout( { allowChange: [ . . . ] })
makeLayout( { props: { placeholder: . . . } })
placeholderText
. This is content that can be placed in blocks like paragraphs and headings, which creates a grayed-out placeholder in the visual editor, prior to the user supplying actual content. You can see this in action in the screenshot below.There's one last thing to do: Configure the WordPress theme-builder, so it knows to include your new custom block. Add the path to your blocks
root directory to the package.json
configuration:
{"atlas": {"config-json": ". / atlas- block- config. json", "theme-dest": ". / wp- theme", "block-css- output- file": "css/ block. css", "block-dirs": [ "node_modules/ @asmartbear/ gutenberg- bridge/ dist", "blocks" ]}}
To see the new block in action, recreate the theme and upload it to WordPress. The new block appears in the insertion menu, including an automated preview, featuring information from the block meta-data:
Here's an example where we enclosed three "Features" in an Atlas Grid
block, so that these features will arrange themselves in a row if there's enough horizontal space, or a column if there's not. Note how the Icon
block is allowing the operator to change the identifier, but none of its other fields:
Back on the React site, everything looks exactly the way it looks in Gutenberg, except now it's responsive to browser widths, changing layout and also diminishing text size when things get narrow, and supporting dark-mode:
Sometimes you'll want to tweak the layout with additional CSS styles. This is a handy way to fine-tune things without having to implement completely new blocks, or to use CSS selector functionality like :hover
.
The layout system automatically applies a CSS class for overall layout block, and a CSS class for each component. The parent layout receives a CSS class based on the uiType
of the block, so in our example, tutorial/
becomes the CSS class tutorial-
. Then, each component inside the layout receives a CSS class of atlas-
, where XYZ
is the atlasId
field.
To implement your CSS classes, all you have to do is create a file called styles.scss
in your block's directory. The WordPress theme builder utility automatically discovers and bundled these into the WordPress theme as well as that front-end CSS file you named using block-
in package.json
. In short, you just create styles.scss
, and everything just works after you rebuild the theme.
In our example, we could add a grey overbar to the Feature's title, like this:
.tutorial- feature { .atlas- layout- headline { border-top: 1px solid #808080;}}
This system works in both React and in Gutenberg, preserving WYSIWYG editing.
Now that we're able to create a pure-layout custom block, we're ready to tackle arbitrarily-complex custom blocks, with properties and fancy Gutenberg editors.