MB Blocks
With the help of MB Blocks, WordPress developers are now able to create Gutenberg blocks using PHP only. There is no JavaScript configuration and build process. The plugin is also compatible with Full-Site Editing, so your blocks can be used to create templates in the FSE.
Here is a screenshot of a custom Gutenberg block (hero area) that's created using MB Blocks:
The preview of the block is displayed in the main content area while the block configuration is displayed on the right. This allows you to edit the block content and live-preview the block in real time. Later, you can also change where the block settings are displayed (on the sidebar or right in the main content area).
Block registration with Meta Box Builder
The easiest way to create a block is using Meta Box Builder. The plugin provides you with the UI to create blocks easily. This is the video on doing that:
Block registration with block.json
WordPress recommends using block.json
for block registration because of these benefits.
MB Blocks supports registering blocks using a block.json
file. It respects WordPress standards so the registration steps are the same as native WordPress block registration.
Creating the block.json file
Assuming we're creating a hero content block, which has 3 fields: title, image, and content, create a block.json
file with the following content. It's recommended to put it in a folder blocks/block-name
(in this example, it's blocks/hero-content
) within your theme, but you can put it anywhere. We'll use the path for registering the block later.
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "meta-box/hero-content",
"title": "Hero Content",
"description": "A custom hero content block that uses MB fields.",
"style": [
"file:./hero-content.css"
],
"category": "formatting",
"icon": "format-quote",
"keywords": [
"hero-content",
"quote"
],
"supports": {
"anchor": true
},
"attributes": {
"image": {
"type": "object",
"default": {
"full_url": "https://example.com/photo.png"
}
},
"title": {
"type": "string",
"default": "Hello, World!"
},
"content": {
"type": "string",
"default": "This is a hero content block."
}
},
"render": "file:./hero-content.php"
}
You can see the syntax is the same as WordPress's JSON specification for the block metadata. The differences are:
- The block name must start with
meta-box/
to make it work with Meta Box. - The
attributes
must be an array of fields, where the field IDs are the properties and the field types and default values are the properties values. These fields must match the Meta Box fields that we will register below.
To create a block.json
file, you can use our Block Generator, which provides a friendly user interface to enter block data.
Registering the block
After creating the block.json
file, you must register it with WordPress. Put the following snippet in your theme or plugin.
function your_prefix_register_blocks() {
// Specify the path to the block.json's folder.
register_block_type( get_template_directory() . '/blocks/hero-content' );
}
add_action( 'init', 'your_prefix_register_blocks' );
Registering block fields
Now you need to register block fields with Meta Box. The block fields must match the fields defined in the block.json
's attributes
property above.
Registering block fields is similar to registering a field group in Meta Box. The only difference is that you must set type
to block
:
add_filter( 'rwmb_meta_boxes', function( $meta_boxes ) {
$meta_boxes[] = [
'title' => 'Hero Content',
'id' => 'hero-content',
'description' => 'A custom hero content block',
'type' => 'block',
// Block fields, must match block.json's attributes.
'fields' => [
[
'type' => 'single_image',
'id' => 'image',
'name' => 'Image',
],
[
'id' => 'title',
'name' => 'Title',
],
[
'type' => 'textarea',
'id' => 'content',
'name' => 'Content',
],
],
];
return $meta_boxes;
} );
After that, you can go to edit a post and insert your block into the post content!
Rendering the block
In the block.json
file, you can specify the PHP template to render the block via the render
parameter.
{
"render": "file:./hero-content.php"
}
(this means render the block with the PHP file hero-content.php
in the same folder as the block.json
file)
By following WordPress standards, these parameters are available in the block template file:
$attributes
: the block attributes, which have all the block settings and fields' data. Attributes are automatically prepared for you so you can access them directly.$content
: the block's inner content.$block
: the block object, an instance ofWP_Block
class.
<div <?= get_block_wrapper_attributes(); ?>>
<?= esc_html( $attributes['title'] ); ?>
<img src="<?= $attributes['image']['full_url'] ?>">
<p><?= $attributes['content'] ?></p>
</div>
Using MB Views
You can also use MB Views to render the block. This is useful when you want to create views with twig, manage JS, CSS from within the Dashboard.
To do so, first, make sure you have the MB Views plugin installed and activated. Then, instead of using file:
prefix, use view:
instead.
{
"render": "view:testimonial"
}
Now create a view by going to Meta Box > Views and create a new view with the name testimonial
. In the view, you can use twig syntax to render the block. For example:
<div {{ mb.get_block_wrapper_attributes() }}>
<img class="testimonial__image" src="{{ attributes.image.full_url }}">
<div class="testimonial__body">
<div class="testimonial__content" style="min-height: 50px;">
<InnerBlocks />
</div>
<div class="testimonial__author">{{ attributes.name }}</div>
</div>
</div>
You can access {{ block }}
, {{ attributes }}
, {{ content }}
in the view like the above example.
Array can be accessed directly by their keys, via dot syntax e.g. {{ attributes.image.full_url }}
, {{ attributes.name }}
.
You can also use CSS and JS tabs in the view to add styles and scripts for the block.
PHP functions need to be prefixed with mb.
to be used in the view.
Set the view's type to Block
and name to testimonial
. Then save the view.
Block styles and scripts
The block.json
allows you to add styles and scripts for blocks as follows. In the value, it’s possible to pass a script handle registered with the wp_register_script
or wp_register_style
functions, a path to a JavaScript/CSS file relative to the block.json
file, or a list with a mix of both.
{
// Editor script: will only be enqueued in the editor.
"editorScript": "file:./index.js",
// Script: will be enqueued both in the editor and on the frontend.
"script": "file:./script.js",
// View script: will be enqueued only on the frontend.
"viewScript": [ "file:./view.js", "example-shared-view-script" ],
// View script module: will be enqueued only on the frontend.
"viewScriptModule": [ "file:./view.js", "example-shared-script-module-id" ],
// Editor style: will only be enqueued in the editor.
"editorStyle": "file:./index.css",
// Style: will be enqueued both in the editor and on the frontend.
"style": [ "file:./style.css", "example-shared-style" ],
// View style: will be enqueued only on the frontend.
"viewStyle": [ "file:./view.css", "example-view-style" ],
}
Block registration without block.json
If you don't want to use block.json
to register blocks, you can do that with pure PHP. The process is similar to registering a field group in Meta Box. The only difference is that you need to add some settings for the block.
Assuming we're creating a hero content block with 3 fields: title, image, and content. Open your theme's functions.php
file (or your plugin's PHP file) and add the following code:
add_filter( 'rwmb_meta_boxes', function( $meta_boxes ) {
$meta_boxes[] = [
'title' => 'Hero Content',
'id' => 'hero-content',
'description' => 'A custom hero content block',
// Block settings.
'type' => 'block',
'icon' => 'awards',
'category' => 'layout',
'context' => 'side',
'render_template' => get_template_directory() . '/blocks/hero/template.php',
'enqueue_style' => get_template_directory_uri() . '/blocks/hero/style.css',
'supports' => [
'align' => ['wide', 'full'],
],
// Block fields.
'fields' => [
[
'type' => 'single_image',
'id' => 'image',
'name' => 'Image',
],
[
'id' => 'title',
'name' => 'Title',
],
[
'type' => 'textarea',
'id' => 'content',
'name' => 'Content',
],
],
];
return $meta_boxes;
} );
The block settings are inherited from the Block JavaScript API with a few differences. See the block registration page on the Gutenberg Handbook if you need more details.
Block settings
title
The block title. It's used to display the block when you click the Block Inserter in Gutenberg.
id
The block ID. Must be unique.
A block ID can only contain lowercase alphanumeric characters and dashes and must begin with a letter. It doesn't accept underscores, i.e. my_block
won't work, but my-block
will work.
version
The block version. This version number is also used to enqueue CSS and JavaScript files to avoid browser caching.
icon
The block icon. Can be any of WordPress' Dashicons (without the prefix dashicons-
), or a custom svg
element (string) or FontAwesome 5 free icons.
Example:
// Specifying a dashicon for the block
'icon' => 'book-alt',
// FontAwesome 5 icon
'icon' => 'fas fa-user',
// Specifying a custom svg for the block
'icon' => '<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path fill="none" d="M0 0h24v24H0V0z" /><path d="M19 13H5v-2h14v2z" /></svg>',
If you need an advanced configuration for the icon, you can set icon
as an array that can contain background and foreground colors, these colors will appear with the icon when they are applicable e.g.: in the inserter.
'icon' => [
// Specifying a background color to appear with the icon e.g.: in the inserter.
'background' => '#7e70af',
// Specifying a color for the icon (optional: if not set, a readable color will be automatically defined)
'foreground' => '#fff',
// Specifying a dashicon for the block
'src' => 'book-alt',
],
description
The block description. Optional.
type
Tells Meta Box to register this as a Gutenberg block (not as a normal meta box). This must be set to block
.
category
Specify the block category, which is used to help users browse and discover them. Available values: text
, media
, design
(default), widgets
, theme
, embed
. If a theme or a plugin registers a custom category, you can use it, too.
keywords
List of keywords that users can use to search the block from the block inserter.
// Make it easier to discover a block with keyword aliases.
'keywords' => ['image', 'photo', 'pics'],
context
Where to show the block settings. If set to side
(default), the block settings are displayed on the right sidebar when you select the block. If set to normal
, the block settings are displayed when you click the Edit icon in the block toolbar.
See the short video below to understand.
supports
Custom supports for the block. This parameter accepts an array like this:
'supports' => [
'align' => ['wide', 'full'],
'customClassName' => true,
'multiple' => true,
'reusable' => true,
'lock' => false,
],
The following parameters are available for supports
:
align
Add supports for the block alignment. Note that your theme must add styling for the Gutenberg alignment.
// Add the support for the block alignment (left, center, right, wide, full).
'align' => true,
// Pick which alignment options to display.
'align' => [ 'left', 'right', 'full' ],
customClassName
This property adds a field to define a custom CSS class name for the block's wrapper. It's useful when you want to add custom styling for a specific instance of the block.
multiple
If you want to have a block that can be inserted into each post one time only (like a hero area block), then set this parameter to false
. A non-multiple block's icon is automatically dimmed (unclickable) to prevent multiple instances.
reusable
A block may want to disable the ability to be converted into a reusable block. By default, all blocks can be converted to reusable blocks. If supports reusable is set to false
, the option to convert the block into a reusable block will not appear.
lock
If you want to remove the support for locking UI, set this parameter to false
.
mode
The default mode of the block: edit
to make it show the edit fields when loaded, preview
(default) to show the rendered HTML when loaded.
'mode' => 'edit',
render_callback
A custom PHP callback or MB Views to display the block content, it accepts the following parameters:
$attributes
: the block attributes, which have all the block settings and fields' data. Attributes are automatically prepared for you so you can access them directly.$content
: the block's inner content.$block
: the block object, an instance ofWP_Block
class.$is_preview
: whether previewing the block in the admin. Deprecated.$post_id
: the current post ID. Deprecated. You can get the post ID withget_the_ID()
.
Please note that you can use all of these parameters regardless of the number of parameters and order.
For example: ( $attributes, $block )
, ( $block, $attributes )
, ( $attributes, $content )
... are valid function signatures.
// Specify a custom PHP callback to display the block.
'render_callback' => 'my_hero_callback',
// Or using $this class method.
'render_callback' => [ $this, 'my_hero_callback' ],
// Or using static method.
'render_callback' => [ 'MyClass', 'my_hero_callback' ],
// You can also use MB Views to render the block by prefixing the view name with `view:`.
'render_callback' => 'view:hero-view',
<?php
function my_hero_callback( $attributes ) {
// Fields's data.
if ( empty( $attributes['data'] ) ) {
return;
}
// Custom CSS class name.
$class = 'hero ' . ( $attributes['className'] ?? '' );
if ( ! empty( $attributes['align'] ) ) {
$class .= " align{$attributes['align']}";
}
?>
<div class="<?= $class ?>" style="background-color: <?= $attributes['background_color'] ?>">
<img class="hero__image" src="<?= $attributes['image']['full_url'] ?>">
<div class="hero__body">
<h2><?= $attributes[ 'title' ] ?></h2>
<div class="hero__content"><?= $attributes[ 'content' ] ?></div>
</div>
</div>
<?php
}
render_template
Sometimes you might want to separate the code that outputs a custom Gutenberg block into a template part, then you can use render_template
parameter to specify the full path to that template part.
'render_template' => get_template_directory() . '/blocks/hero/template.php',
Inside the template file, you have full access to these parameters, just like render_callback
:
$attributes
: the block attributes, which have all the block settings and fields' data. Attributes are automatically prepared for you so you can access them directly.$content
: the block's inner content.$block
: the block object, an instance ofWP_Block
class.$is_preview
: whether previewing the block in the admin. Deprecated.$post_id
: the current post ID. Deprecated. You can get the post ID withget_the_ID()
.
So, inside the blocks/hero/template.php
, you can write:
<?php
// Fields' data.
if ( empty( $attributes['data'] ) ) {
return;
}
// Custom CSS class name.
$class = 'hero ' . ( $attributes['className'] ?? '' );
if ( ! empty( $attributes['align'] ) ) {
$class .= " align{$attributes['align']}";
}
?>
<div class="<?= $class ?>" style="background-color: <?= $attributes[ 'background_color' ] ?>">
<img class="hero__image" src="<?= $attributes['image']['full_url'] ?>">
<div class="hero__body">
<h2><?= $attributes[ 'title' ] ?></h2>
<div class="hero__content"><?= $attributes[ 'content' ] ?></div>
</div>
</div>
enqueue_style
If you want to specify a custom styling for this specific block, then set this parameter to the URL of the custom CSS file that will be used to style the block.
'enqueue_style' => get_template_directory_uri() . '/blocks/hero/style.css',
If you have multiple blocks, then using multiple CSS files might hurt the performance of your website since you have many CSS files enqueued. In that case, please put the styles in your theme, and use the functions enqueue_block_assets() and enqueue_block_editor_assets() to enqueue your styles.
enqueue_script
If your block requires custom JavaScript actions, then set this parameter to the URL of the custom JavaScript file that will be used to do JavaScript tasks for the block (like initializing a slider).
'enqueue_script' => get_template_directory_uri() . '/blocks/hero/script.js',
Please note that this script should be run in 2 cases:
- When the block is done loading on the front end
- When the block preview is done loading in the block editor on the back end
On the back end, every time you modify the block settings, the block preview is re-rendered. The whole HTML of the block preview will be replaced by the new HTML.
So, to trigger a custom code when the block preview is loaded, you need to add an event listener to the event mb_blocks_preview/{$block_id}
and run your code there:
// Run when a block preview is done loading.
$( document ).on( 'mb_blocks_preview/hero-area', function( e ) {
console.log( e.target ); // e.target is the wrapper div of the block.
// Do something.
} );
To make it work for both the front end and back end, you can write your JavaScript like this:
( function( $ ) {
function init() {
// Do something.
}
// Run when a document ready on the front end.
$( document ).ready( init );
// Run when a block preview is done loading.
$( document ).on( 'mb_blocks_preview/hero-area', init );
} )( jQuery );
Note that jQuery is already added as a dependency for the script, so you can use it in your script.
enqueue_assets
If your block has some CSS / JavaScript dependencies (such as a JavaScript library), then using enqueue_style
and enqueue_script
might not be a good option since it allows you to enqueue only one single CSS / JS file.
In that case, use enqueue_assets
to enqueue your assets. This parameter accepts a PHP callback function, like this:
'enqueue_assets' => function() {
wp_enqueue_style( 'slick', '//cdn.jsdelivr.net/npm/[email protected]/slick/slick.css', [], '1.8.1' );
wp_enqueue_script( 'slick', '//cdn.jsdelivr.net/npm/[email protected]/slick/slick.min.js', ['jquery'], '1.8.1', true );
wp_enqueue_script( 'my-custom-script', get_template_directory_uri() . '/blocks/hero/script.js', ['slick'], '', true );
}
preview
This attribute allows you to set preview data for the block, which will show when you click on the plus icon (+) on the toolbar:
The block preview is just the block rendered with sample data. And you'll just need to set the parameter preview
as an array of that sample data.
For example, if you have a "Team Member" block (as above) that has 3 fields: image, title, and description, you can set the preview
parameter as follows:
'preview' => [
'image' => 'https://domain.com/person.jpg', // Image URL
'title' => 'William Shakespeare',
'description' => 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam',
]
storage_type
Sets the storage for the block fields. Default, it's attributes
, which means saving block fields in the attributes.
If you want to save the block fields into custom fields, set it to post_meta
. Saving block fields in the custom fields makes the block act as a wrapper of custom fields. In this case, to prevent bugs, you should set multiple
to false
to prevent inserting the same block multiple times (see supports
parameter above).
If you want to save the block fields into custom tables, you need to activate the MB Custom Table extension first. Then set storage_type
and table
as follows:
'storage_type' => 'custom_table',
'table' => 'your table name',
See MB Custom Table documentation for more details.
Block fields
Each block can have unlimited fields. Adding fields to blocks is similar to adding fields to a custom meta box. All you need to do is specify the fields in the parameter fields
from the block settings.
add_filter( 'rwmb_meta_boxes', function( $meta_boxes ) {
$meta_boxes[] = [
// Other block settings.
// Block fields.
'fields' => [
[
'type' => 'single_image',
'id' => 'image',
'name' => 'Image',
],
[
'id' => 'title',
'name' => 'Title',
],
// Other fields,
],
];
return $meta_boxes;
} );
Each field is an array of its settings. See this guide for details about field settings.
Block rendering
There are various ways to render a block (via render
property if you use block.json
or via render_callback
or render_template
if you don't use block.json
). In any case, the plugin provides you these variables that you can use:
$attributes
: the block attributes, which have all the block settings and fields' data. Attributes are automatically prepared for you so you can access them directly.$content
: the block's inner content.$block
: the block object, an instance ofWP_Block
class..
Automatically prepare attributes
By default, all attributes inside $attributes
are automatically prepared for you. $attributes[ $field_id ]
returns the value of the rwmb_get_value()
function, which gives you all the data for the field.
For example, if you have a single_image
field, the value of that field is stored as a number (attachment ID). But when you access the field value via $attributes['image']
, you'll get the whole attachment object like below, which is more convenient to use:
[
'ID' => 123,
'name' => 'logo-150x80.png',
'path' => '/var/www/wp-content/uploads/logo-150x80.png',
'url' => 'https://example.com/wp-content/uploads/logo-150x80.png',
'width' => 150,
'height' => 80,
'full_url' => 'https://example.com/wp-content/uploads/logo.png',
'title' => 'Logo',
'caption' => 'Logo caption',
'description' => 'Used in the header',
'alt' => 'Logo ALT text',
'srcset' => 'large.jpg 1920w, medium.jpg 960w, small.jpg 480w', // List of responsive image src
'sizes' => [], // List of image sizes. See https://developer.wordpress.org/reference/functions/wp_get_attachment_metadata/
'image_meta' => [], // List of image meta. See https://developer.wordpress.org/reference/functions/wp_get_attachment_metadata/
]
And you can use it in your block template like this:
<img src="<?= $attributes['image']['full_url'] ?>">
This preparation is helpful for not-simple fields like image, file, post, taxonomy, etc.
Accessing raw data
In case you want to access the raw data (e.g., the attachment ID), you can use the data
key inside $attributes
. $attributes['data']
contains all the info of fields as an array in the format of 'field_id' => 'field_value'
.
Note that, unlike $attributes[ $field_id ]
, the field value in $attributes['data']
is not prepared, which means it's the raw value.
For example, for a single_image
field, the value of $attributes['data']['image']
is the attachment ID.
Rendering helper functions
In addition to the automatic preparation of attributes, to make it easier to access the block fields' data, we created 2 helper functions: mb_get_block_field()
and mb_the_block_field()
.
These functions work exactly like the rwmb_get_value()
and rwmb_the_value()
, but applied for the current block only. The first function returns the data stored for a block field, while the 2nd one outputs that data.
// Get block image field.
$image = mb_get_block_field( 'image' );
echo $image['full_url'];
// Output the block content field.
mb_the_block_field( 'content' );
Reserved attributes
When you create a block, there are some reserved attributes that you should avoid using for field's ID, unless your purpose is to override the default MB Block's behavior. These attributes are:
id
: the auto generated ID for the block, which is unique for each block.name
: the block name.
These attributes are used by MB Blocks for easier to style and manipulate the block. If you a field with IDs id
or name
, the field's value will override the default value generated by MB Blocks.
In that case, if you want to get the block name, you can use the variable $block->name
. $block
is a variable that is always available in your template (or callback). It's an instance of the WP_Block
class.
Deprecated parameters
These parameters are available in the previous versions of MB Blocks and are deprecated since 1.5.0. They're still working but will be removed in the future. Please use the alternative methods instead.
$is_preview
: a boolean variable to let you know if you're in the preview mode for Gutenberg or on the front end. It's useful when you want to display a custom message to users when they edit the block on the back end. To check if the active block is in preview mode, usedefined( 'REST_REQUEST' ) && REST_REQUEST
instead.$post_id
: the current post ID. You can access viaget_the_ID()
function instead.
Inner blocks
WordPress has an amazing feature for Gutenberg blocks called InnerBlocks, which allows you to insert other blocks inside a block. Since version 1.4, MB Blocks also supports this feature.
Assuming you want to create a custom testimonial block, which has the following data:
- An image
- A title
- A paragraph for the testimonial content
- And a select field for the testimonial style (something like an image on the right or above the content)
It's easy to make those fields with MB Blocks. However, it might be less flexible than using the default Gutenberg heading and paragraph blocks for the title and content field. So, we might want to wrap those 2 fields into a InnerBlocks
like this:
- Image
- InnerBlocks
- Style
This is an example code of the block:
<?php
add_filter( 'rwmb_meta_boxes', function( $meta_boxes ) {
$meta_boxes[] = [
'title' => 'Testimonial',
'id' => 'testimonial',
'type' => 'block',
'context' => 'side',
'render_callback' => function( $attributes ) {
?>
<div class="testimonial testimonial--<?= $attributes['style'] ?>">
<div class="testimonial__text">
<InnerBlocks />
</div>
<div class="testimonial__image">
<?php mb_the_block_field( 'image' ) ?>
</div>
</div>
<?php
},
'fields' => [
[
'type' => 'select',
'id' => 'style',
'name' => 'Style',
'options' => [
'default' => 'Default',
'image_above' => 'Image above',
],
],
[
'type' => 'single_image',
'id' => 'image',
'name' => 'Image',
],
],
];
return $meta_boxes;
} );
When inserting a field in the admin, you'll see the block like this:
As you can see the InnerBlocks on the left, where the usual placeholder is displayed "Type / to choose a block". And you can insert headings (of any type H1, H2, H3, etc.) and the content very easily.
I use Wayfinder plugin to show the block outline, which makes it easier to see which blocks are being edited.
<InnerBlocks class="testimonial__text" />
To make it more powerful, MB Blocks supports the following properties of InnerBlocks. They're the same as in the block handbook.
allowedBlocks
allowedBlocks
helps you to restrict blocks that are available to insert into the InnerBlocks. The blocks that are not specified, will be not available to be inserted.
In your template (or render callback), you can set allowedBlocks
like this:
<InnerBlocks
allowedBlocks="<?= esc_attr( json_encode( [
'core/heading',
'core/paragraph',
] ) ) ?>"
/>
This allows you to insert only heading and paragraph blocks.
orientation
By default, InnerBlocks expects its blocks to be shown in a vertical list. A valid use case is to style InnerBlocks to appear horizontally. When blocks are styled in such a way, the orientation prop can be used to indicate a horizontal layout:
<InnerBlocks orientation="horizontal" />
template
Use the template property to define a set of blocks that prefill the InnerBlocks component when inserted. You can set attributes on the blocks to define their use. The example below shows a book review template using InnerBlocks component and setting placeholder values to show the block usage.
<InnerBlocks
template="<?= esc_attr( json_encode( [
[ 'core/heading', [ 'placeholder' => 'Enter testimonial title...' ] ],
[ 'core/paragraph', [ 'placeholder' => 'Enter testimonial content...' ] ],
] ) ) ?>"
/>
templateLock
Template locking allows locking the InnerBlocks area for the current template. Options:
all
— prevents all operations. It is not possible to insert new blocks. Move existing blocks or delete them.insert
— prevents inserting or removing blocks, but allows moving existing ones.false
— prevents locking from being applied to an InnerBlocks area even if a parent block contains locking. ( Boolean )
If locking is not set in an InnerBlocks area: the locking of the parent InnerBlocks area is used.
If the block is a top-level block: the locking of the Custom Post Type is used.
Wrapper div issue
By default, WordPress will create a couple of wrappers <div>
for inner blocks in the editor (in the admin) to function, this causes inconsistent styling for the editor and the frontend. For example, if you create inner blocks structure like this:
<div class="my-block">
<div class="my-block__inner">
<InnerBlocks />
</div>
</div>
If you add items to the inner blocks, in the frontend, its structure looks like this:
<div class="my-block">
<div class="my-block__inner">
<h2>My heading</h2>
<p>My content</p>
</div>
</div>
However, in the editor, it will render like this (e.g. two extra div
):
<div class="my-block">
<div class="my-block__inner">
<div class="block-editor-block-list__block wp-block is-selected ...">
<div>
<h2>My heading</h2>
<p>My content</p>
</div>
</div>
</div>
</div>
This causes the editor and the frontend have different markup, which makes it hard to style the block consistently in both places using the same CSS.
To fix this, MB Blocks lets you remove two extra div
of inner blocks in the admin by adding class
, id
, or style
directly to <InnerBlocks />
. So, instead of writing:
<div class="my-block">
<div class="my-block__inner">
<InnerBlocks />
</div>
</div>
You should write:
<div class="my-block">
<InnerBlocks class="my-block__inner" />
</div>
By doing this, it tells WordPress that MB Blocks will control the output of inner blocks in the editor, so both editor and front end will rendered like:
<div class="my-block">
<div class="my-block__inner">
<h2>My heading</h2>
<p>My content</p>
</div>
</div>
Block templates
Sometimes you want to load default blocks when creating a new post. Block templates allow specifying a default initial state for an editor session. Use the argument template
when registering the post type:
'template' => [
['meta-box/{$block_id}']
]
Block data
Each block created using MB Blocks is a dynamic block. By default, the block data is saved as a JSON string in the block content.
If you view the post content via a tool like PHPMyAdmin, you'll see the block is stored as a string like this:
<!-- wp:meta-box/hero-content {"id":"block_jyqlhbauqz4jz51ahab","data":{"image":"10","title":"Hi, I’m Martin Green","subtitle":"WEB DEVELOPER \u0026 DESIGNER","content":"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusa ntium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta suntlo explica bo. Nemo enim ipsam voluptatem quia voluptas.","signature":"9","button_text":"Discover More","button_url":"#","background_color":"#f5f7f8"},"align":"wide"} /-->
When you decode the JSON string, you'll see the block data as an object like this:
{
"id": "block_jyqlhbauqz4jz51ahab",
"data": {
"image": "10",
"title": "Hi, I’m Martin Green",
"subtitle": "WEB DEVELOPER \u0026 DESIGNER",
"content": "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusa ntium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta suntlo explica bo. Nemo enim ipsam voluptatem quia voluptas.",
"signature": "9",
"button_text": "Discover More",
"button_url": "#",
"background_color": "#f5f7f8"
},
"align": "wide"
}
It has the following attributes:
name
: the block name. Note that if you have a field with IDname
, the field value will overwrite this property. In this case, if you want to get the block name, you can use the variable$block->name
.id
: a unique ID for the block. Note that it's different from the block settings ID. This ID can be used to set theid
parameter in the HTML if you want.align
: block alignmentanchor
: block anchorclassName
: custom CSS class for the blockdata
: an array of the block fields' data, in the format of'field_id' => 'field_value'
The data is passed to the render_callback
or render_template
as a $attributes
parameter. So you can use it to render the block. See the block rendering section for more details.
Saving block data in post meta or custom tables
Besides saving the block data as a JSON string in the block's attributes, the plugin allows you to save data in post meta or custom tables. This makes blocks behave the same as a normal field group.
If you want to save block data in post meta, in the meta box's group, set the storage_type
to post_meta
:
[
'storage_type' => 'post_meta',
'supports' => [
'multiple' => false,
],
]
In this case, to prevent bugs, you should set multiple
to false
to prevent inserting the same block multiple times (the codes above already have that).
If you want to save the block fields into custom tables, you need to activate the MB Custom Table extension first. Then set storage_type
and table
as follows:
[
'storage_type' => 'custom_table',
'table' => 'your_table_name',
'supports' => [
'multiple' => false,
],
]
When saving block data in post meta or custom tables, there is no attributes stored in the block itself.
Automatic preparation of attributes is not available, helpers functions like mb_get_block_field()
and mb_the_block_field()
will not work.
You will have to use the rwmb_meta function to get the block data.
Hooks
mb_${blockId}_settings
This is a filter to let developers change the block settings via Javascript. It accepts one parameter - settings
, the block settings array.
In this filter, blockId
is the block ID, which has the format meta-box/id
where id
is the field group ID.
To use a JavaScript hook, please refer to this tutorial.
Video Tutorial
Create Custom Gutenberg Blocks With Meta Box (only PHP)
Build Gutenberg Blocks Visually With Meta Box Builder
See more details on using Meta Box Builder with MB Blocks.
Examples
The complete code example for the video (and used to write this tutorial) is available in the Library. You can copy the code and put it in your theme. Then start to modify it to create your own Gutenberg blocks.