Learning Block.json – A deep dive into how Block.json Works

Things I Learned About Block.json
License: Adobe Stock

I have an emotional trigger whenever I hear something about Block.json. It was always in the back of my mind saying I should learn it. After all, it is how modern blocks should be built.

But I put off the switch. The existing blocks I have are working and are going to be fine. So this Block.json thing annoyed me.

Then I saw it in enterprise use.

My First Experience with Block.json

I had created a block for a client using my existing knowledge (without Block.json).

I submitted it for code-review, and when it came back I discovered the code had been refactored to include Block.json.

I took one look at the file… and as Cher in Clueless would say: As if!

I was not sold on it.

A Cursory Look into Block.json

I took a dive deeper into Block.json, and just concluded that anything that Block.json could do… I could do.

I’m used to rendering my blocks via PHP, so I figured Block.json was not right for me.

So I procrastinated. I concentrated on other things.

But a side-project did come to mind. It would be my first pure block plugin.

And so I began the journey of creating a block with Block.json support.

A Brief Introduction to Block.json

When researching Block.json for the first time, I went to the almighty Google. I typed in “what is block json”. The first relevant site was the WordPress Block.json documentation.

Block.json markup was, well, JSON.

It had most of the things I expected to have when registering the block via PHP and JS. I’ll go over these in more detail in a bit.

The Block.json Schema

One great benefit of Block.json is its schema.

When I started with blocks, the attributes really messed me up. Should I use bool or boolean? Should I use number or int? Are there other data types I’m screwing up here?

With a schema, you can look directly at the source and see what accepts what.

A list of Block.json attribute types
A list of Block.json attribute types

Looking at the schema, here are the data types available for use:

  • null
  • boolean
  • object
  • array
  • string
  • integer
  • number

It’s little bit confusing, but at least I figured out what the datatypes actually were.

Compare and Contrast: Block.json vs the Old Way

As I dove deeper into Block.json, I discovered a one-to-one relationship for most items. I’ll compare the Block.json schema for my latest plugin to an older way using my plugin Highlight and Share.

The Block Title

The title is the name of your block. It is used in the block preview and the block sidebar.

Here’s Block.json’s title parameter.

Block.json Title
Block.json Title

Compared to Highlight and Share, here’s where the title would be set:

Register Block Type Title
Register Block Type Title

The Block Description

The block description shows in the block preview and also in the block’s sidebar options.

Block Sidebar Showing the Description
Block Sidebar Showing the Description
Block Description in the Block Preview
Block Description in the Block Preview

When creating your description, you can place this into your Block.json or the old way using registerBlockType.

Block Description Using Block.json
Block Description Using Block.json
Block Description Using registerBlockType
Block Description Using registerBlockType

The Block Namespace

The “name” option in Block.json is the namespace for your block (e.g., has/click-to-share).

Here’s an example of the namespace in PHP and JS (without Block.json).

register_block_type(
	'has/click-to-share',
	...
);Code language: PHP (php)
registerBlockType('has/click-to-share', {
...
} );Code language: JavaScript (javascript)

Here is the namespace (i.e., name) for the block in Block.json.

{
	...
	"name": "mediaron/quotes-dlx",
	...
}Code language: JSON / JSON with Comments (json)

A benefit of Block.json in this scenario is that you only have to set the namespace once.

Category

The block category is where you’d like your block to show up when a user hits the “+” button to insert a block in the block editor.

The category types are as follows:

  • text
  • common
  • media
  • design
  • widgets
  • theme
  • embed

Source: How to Create a Custom Blocks Category for WordPress.

You can also create your own categories using the hook block_categories_all.

Armed with your block category, there’s little difference between Block.json and registering your block the “old” way.

registerBlockType('has/click-to-share', {
	...
	category: 'common',
	...
} );Code language: JavaScript (javascript)

And the Block.json way:

{
	...
	"category": "text",
	...
}Code language: JSON / JSON with Comments (json)

Setting an Icon

Setting an icon is fairly straightforward in both block registration and Block.json.

You can either use a Dashicon or include an SVG. If you choose to use JS registration, you can easily convert your SVGs into React-friendly format using SVGR Playground.

Here’s an example using the “old” way:

registerBlockType('has/click-to-share', {
	...
	icon: (
		<svg
			aria-hidden='true'
			focusable='false'
			data-prefix='fas'
			data-icon='share-alt'
			className='svg-inline--fa fa-share-alt fa-w-14'
			role='img'
			xmlns='http://www.w3.org/2000/svg'
			viewBox='0 0 448 512'
		>
			<path
				fill='currentColor'
				d='M352 320c-22.608 0-43.387 7.819-59.79 20.895l-102.486-64.054a96.551 96.551 0 0 0 0-41.683l102.486-64.054C308.613 184.181 329.392 192 352 192c53.019 0 96-42.981 96-96S405.019 0 352 0s-96 42.981-96 96c0 7.158.79 14.13 2.276 20.841L155.79 180.895C139.387 167.819 118.608 160 96 160c-53.019 0-96 42.981-96 96s42.981 96 96 96c22.608 0 43.387-7.819 59.79-20.895l102.486 64.054A96.301 96.301 0 0 0 256 416c0 53.019 42.981 96 96 96s96-42.981 96-96-42.981-96-96-96z'
			></path>
		</svg>
	),
	...
});Code language: JavaScript (javascript)

And using Block.json:

{
	...
	"icon": ""<svg width='100%' height='100%' viewBox='0 0 4450 4450' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xml:space='preserve' xmlns:serif='http://www.serif.com/' style='fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;''><g transform='matrix(4.16667,0,0,4.16667,-1325.8,-2025.45)'><path fill='#9932cc' d='M852.07,1553.89C1146.14,1553.89 1385.98,1314.05 1385.98,1020.01C1385.98,725.948 1146.14,486.109 852.07,486.109C558.033,486.109 318.193,725.948 318.193,1020.01C318.193,1314.05 558.033,1553.89 852.07,1553.89Z'/><path d='M645.766,833.41C718.162,813.992 792.571,856.965 811.989,929.362C838.72,1029.11 795.378,1186.69 610.36,1211.24C650.471,1170.11 675.614,1140.15 686.018,1100.12C624.08,1102.5 566.509,1062 549.813,999.605C530.396,927.208 573.368,852.798 645.766,833.41Z' style='fill:white;'/><path d='M988.445,833.41C1060.84,813.992 1135.28,856.965 1154.67,929.362C1181.4,1029.11 1138.09,1186.69 953.069,1211.24C993.151,1170.11 1018.29,1140.15 1028.7,1100.12C966.761,1102.5 909.188,1062 892.493,999.605C873.104,927.208 916.049,852.798 988.445,833.41Z' style='fill:white;'/></g></svg>"",
	...
}Code language: JSON / JSON with Comments (json)

Extra quotes so SVG doesn’t render in the browser.

Setting Keywords

Keywords help users who search for your block either using “/” (slash) commands, or when inserting your block via the block inserter.

With the registerBlockType way, setting keywords is as simple as passing a JavaScript array:

registerBlockType('has/click-to-share', {
	...
	keywords: [
		__('click', 'highlight-and-share'),
		__('social', 'highlight-and-share'),
		__('better', 'highlight-and-share'),
		__('tweet', 'highlight-and-share'),
		__('twitter', 'highlight-and-share'),
		__('facebook', 'highlight-and-share'),
		__('share', 'highlight-and-share'),
		__('feature', 'highlight-and-share'),
	],
	...
});Code language: JavaScript (javascript)

And this is how they are registered in Block.json:

{
	...
	"keywords": ["click", "tweet", "twitter", "share", "quote", "blockquote", "dlx", "quotes", "dlx", "quo"],
	...
}Code language: JSON / JSON with Comments (json)

Setting the Block Version

The version parameter doesn’t really exist when registering your block. This allows you to version your block separately from your plugin version.

An example of doing this in Block.json is:

{
	...
	"version": "1.0.0",
	...
}Code language: JSON / JSON with Comments (json)

Setting the Textdomain

Within Block.json, you can specify the textdomain:

{
	...
	"textdomain": "quotes-dlx",
	...
}Code language: JSON / JSON with Comments (json)

Setting your textdomain is a complicated endeavor . Here’s a really good tutorial on how to set your textdomain for your plugin using Block.json.

Setting and Passing Attributes

The attributes parameter is a bit different if you are used to registering them with PHP.

Here’s an example using PHP:

register_block_type(
	'has/click-to-share',
	array(
		'attributes'      => array(
			'shareText'          => array(
				'type'    => 'string',
				'default' => '',
			),
			...
		)
	)
);Code language: PHP (php)

And here’s registering attributes via Block.json:

{
	...
	"attributes": {
		"show_copy": {
			"type": "boolean",
			"default": true
		},
		"show_permalink": {
			"type": "boolean",
			"default": true
		}
	},
	...
}Code language: JSON / JSON with Comments (json)

The cool thing about Block.json here is that you can register and update your attributes without having to dive into PHP or re-running your build tools.

Enabling and Setting Block Previews

Using the example parameter, you can pass attribute values so your block can render a preview (think of this as short-circuiting your block).

Block Preview
Block Preview in the Block Editor

Here’s how I passed attributes to my block using registerBlockType:

registerBlockType('has/click-to-share', {
	...
	example: {
		attributes: {
			preview: true,
		},
	},
	...
});Code language: JavaScript (javascript)

And here’s how I did it in Block.json:

{
	...
	"example": {
		"attributes": {
			"preview": true,
			"blockOnly": true,
			"share_text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque malesuada dui id nisi vulputate semper. Nam sagittis ac nulla id pharetra. Maecenas congue, tellus a blandit cursus, lorem dolor hendrerit erat, sed luctus arcu velit eget ligula.",
			"template": "purple-bliss",
			"enable_contextual_menu": true,
			"enable_copy_text": true,
			"enable_copy_tweet": true,
			"enable_copy_link": true,
			"enable_tweet_this": true,
			"maximum_width": 800,
			"maximum_width_unit": "px"
		}
	},
	...
}Code language: JSON / JSON with Comments (json)

If you need help with previews, I wrote a tutorial on how to enable the block previews.

Setting What Your Block Supports

There are many (many) ways to explicitly tell what your block supports (e.g, colors, alignment, anchor).

Here’s how I set up my “supports” parameter the old way:

registerBlockType('has/click-to-share', {
	...
	supports: {
		anchor: true,
		html: false,
	},
	...
});Code language: JavaScript (javascript)

And using Block.json:

{
	...
	"supports": {
		"anchor": true,
		"align": true,
		"className": true
	},
	...
}Code language: JSON / JSON with Comments (json)

Setting up Scripts and Styles

When I registered my block using PHP and JS, I referenced the scripts I needed using register_block_type.

register_block_type(
	'has/click-to-share',
	array(
		...
		'editor_script'   => 'has-click-to-share',
		'editor_style'    => 'has-style-admin-css',
		...
	)
);Code language: PHP (php)

I just passed the handles of my script and CSS handles that I registered.

With Block.json, you have a little more control.

{
	...
	"editorScript": "quotes-dlx-block",
	"editorStyle": "quotes-dlx-block-editor-styles",
	"style": "quotes-dlx-frontend",
	"viewScript": "quotes-dlx-actions"
	...
}Code language: JSON / JSON with Comments (json)

One cool thing about Block.json is you can actually reference a relative file instead of a script or style handle.

For example, here’s an example of loading in a file instead:

{ "editorScript": "file:./build/index.js" }Code language: JSON / JSON with Comments (json)

Depending on where you place your Block.json file, you can just include your file and WordPress and Block.json will take it from there.

What I’ve found, however, is this feature is quirky and still buggy. As a result, I had to use script and style handles instead of loading the files directly using Block.json.

Here’s a brief summary of the various parameters that Block.json can handle:

  • editorScript: file location to your script, or enqueue handle (loads in the Block Editor)
  • editorStyle: file location to your script, or enqueue handle (loads in the Block Editor)
  • style: file location to your frontend and backend styles, or enqueue handle (loads on the frontend and backend)
  • viewScript: any scripts you’d like to load on the frontend (takes a file location or enqueue handle)

The API Version

I decided to use API version 2 since it’s the latest and I wanted to be up-to-date.

{
	...
	"apiVersion": 2,
	...
}Code language: JSON / JSON with Comments (json)

There is one caveat with using version 2 of the Block.json API: you need to add markup in your block to support it.

I started off using API version 1. Everything in my block worked fine and I was able to style it in the editor.

Then I switched to API version 2. All my block styles were gone. There was no wrapper around my block. It was impossible to style.

It took a lot of searching, but I finally found the culprit on the WordPress Make Blogs.

So how do you opt in? Well, you’ll need to use the useBlockProps hook and wrap your Block output around it.

useBlockProps is in the @wordpress/block-editor import.

Here’s an example of importing useBlockProps.

import {
	InspectorControls,
	RichText,
	BlockControls,
	useBlockProps,
} from '@wordpress/block-editor';
Code language: JavaScript (javascript)

I then included a wrapper div and passed in the block props towards the end of my block render.

const blockProps = useBlockProps( {
	className: `quotes-dlx template-${ template }`,
} );

if ( preview ) {
	return <div { ...blockProps }>{ previewBlock }</div>;
	// eslint-disable-next-line no-else-return
} else {
	return <div { ...blockProps }>{ block }</div>;
}Code language: JavaScript (javascript)

I was able to style my block once again.

Block.json Parameters Conclusion

In conclusion, here are the parameters that I’ve used so far:

  • title: The title of the block
  • apiVersion: Which Block.json API version to use
  • name: The namespace for your block (e.g., mediaron/quotes-dlx)
  • category: Which category you’d like to use for your block
  • icon: Dashicon or SVG
  • description: Your block description
  • keywords: JS array of keywords
  • version: Version of your block
  • textdomain: The text domain of your plugin and/or block
  • attributes: JSON attribute options
  • example: JSON attributes for generating a block preview
  • supports: What editor features you’d like to enable
  • editorScript: file location to your script, or enqueue handle (loads in the Block Editor)
  • editorStyle: file location to your script, or enqueue handle (loads in the Block Editor)
  • style: file location to your frontend and block editor styles, or enqueue handle (loads on the frontend/backend)
  • viewScript: any scripts you’d like to load on the frontend (takes a file location or enqueue handle)

Registering Scripts and Styles via PHP

One thing I learned while registering scripts and styles is that it’s a lot of trial and error to make sure they load in the appropriate place (e.g., block JS only loads in the Block Editor).

For example, I usually register my block scripts using enqueue_block_editor_assets.

add_action( 'enqueue_block_editor_assets', 'has_blocks_editor_assets' );Code language: PHP (php)

Within the has_blocks_editor_assets function, I would register the scripts and styles I needed so that I could use their handles later.

Here’s a sample of the callback when registering scripts and styles for the Block Editor:

/**
 * Enqueue assets for backend editor
 *
 * @since 1.0.0
 */
function has_blocks_editor_assets() {

	wp_register_style(
		'has-style-admin-css',
		Highlight_And_Share::get_instance()->get_plugin_url( 'dist/has-cts-editor.css' ),
		array(),
		HIGHLIGHT_AND_SHARE_VERSION,
		'all'
	);
	wp_register_script(
		'has-click-to-share',
		Highlight_And_Share::get_instance()->get_plugin_url( 'dist/has-cts.js' ),
		array( 'wp-blocks', 'wp-element', 'wp-i18n' ),
		HIGHLIGHT_AND_SHARE_VERSION,
		true
	);

	wp_localize_script(
		'has-click-to-share',
		'has_gutenberg',
		array(
			'svg'    => Highlight_And_Share::get_instance()->get_plugin_url( 'img/share.svg' ),
		)
	);
	wp_set_script_translations( 'has-click-to-share', 'highlight-and-share' );
	do_action( 'has_enqueue_block_styles_scripts' );
}

add_action( 'enqueue_block_editor_assets', 'has_blocks_editor_assets' );Code language: PHP (php)

I can then register my block in PHP using the init WordPress action.

add_action( 'init', 'has_register_block_attributes' );Code language: PHP (php)

And then register my block:

register_block_type(
	'has/click-to-share',
	array(
		'attributes'      => array(
			'shareText' => array(
				'type'    => 'string',
				'default' => '',
			),
		),
		'render_callback' => 'has_click_to_share',
		'editor_script'   => 'has-click-to-share',
		'editor_style'    => 'has-style-admin-css',
	)
);Code language: PHP (php)

Since I’m registering my scripts and styles, I can just use the handles in register_block_type.

One confusing part of all this is what loads where. For example, editor_script should load only in the Block Editor. Likewise for editor_style.

There’s also a style option, which I’ve found loads your styles in the Block Editor and also on the Frontend.

Here are the official definitions for styles/scripts I’ve found on the web.

  • style: Loads scripts on the frontend and in the Block Editor
  • view_script: Loads scripts on the frontend for your block
  • script: Loads scripts on the frontend and the Block Editor
  • editor_script: Only loads in the Block Editor for your block
  • editor_style: Only loads in the Block Editor

Registering Scripts and Styles via Block.json

As mentioned earlier, here are the JSON parameters you can use to register scripts and styles.

  • editorScript: file location to your script, or enqueue handle (loads in the Block Editor)
  • editorStyle: file location to your script, or enqueue handle (loads in the Block Editor)
  • style: file location to your frontend/backend styles, or enqueue handle (loads on the frontend and backend)
  • script: file location to your frontend/backend scripts, or enqueue handle (loads on the frontend and backend)
  • viewScript: any scripts you’d like to load on the frontend (takes a file location or enqueue handle)

Here’s an example using editorStyle to reference a stylesheet in a root folder called build.

{ "editorStyle": "file:./build/index.css" }Code language: JSON / JSON with Comments (json)

You can even use array syntax to load multiple files:

"editorStyle": ["file:./build/index.css", "file:./build/index2.css"]Code language: JSON / JSON with Comments (json)

However, I chose to use PHP to handle my style and script registering as some of the parameters I’ve found don’t always work when using the file path.

I’d use the following hooks to point to my registration methods:

// Enqueue general front-end style.
add_action( 'wp_enqueue_scripts', array( $this, 'register_frontend_scripts' ) );

// Enqueue block assets.
add_action( 'enqueue_block_editor_assets', array( $this, 'register_block_editor_scripts' ) );Code language: PHP (php)

Here’s the contents of my register_frontend_scripts callback.

/**
 * Register front-end scripts/styles.
 */
public function register_frontend_scripts() {
	$theme_deps = $this->register_theme_styles();

	wp_register_style(
		'quotes-dlx-frontend',
		Functions::get_plugin_url( 'dist/quotes-dlx-frontend.css' ),
		$theme_deps,
		Functions::get_plugin_version(),
		'all'
	);

	if ( has_block( 'mediaron/quotes-dlx' ) ) {
		wp_enqueue_script(
			'quotes-dlx-actions',
			Functions::get_plugin_url( 'dist/quotes-dlx-actions.js' ),
			array( 'wp-i18n', 'wp-a11y' ),
			Functions::get_plugin_version(),
			true
		);
	}

}Code language: PHP (php)

You’ll notice I created a CSS handle of: quotes-dlx-frontend.

Here’s my callback for register_block_editor_scripts:

/**
 * Register the block editor script with localized vars.
 */
public function register_block_editor_scripts() {
	...

	// Register styles here because array in block.json fails when using array of styles (enqueues wrong script).
	wp_register_style(
		'quotes-dlx-block-editor',
		Functions::get_plugin_url( 'dist/quotes-dlx-block-editor.css' ),
		$theme_deps,
		Functions::get_plugin_version(),
		'all'
	);
	wp_register_style(
		'quotes-dlx-block-editor-styles',
		Functions::get_plugin_url( 'build/quotes-dlx.css' ),
		array( 'quotes-dlx-block-editor' ),
		Functions::get_plugin_version(),
		'all'
	);

	wp_register_script(
		'quotes-dlx-block',
		Functions::get_plugin_url( 'build/quotes-dlx.js' ),
		array(),
		Functions::get_plugin_version(),
		true
	);
	...
}Code language: PHP (php)

The handles I created are:

  1. quotes-dlx-block-editor
  2. quotes-dlx-block-editor-styles
  3. quotes-dlx-block

I then pass those handles to Block.json

{
	"editorScript": "quotes-dlx-block",
	"editorStyle": "quotes-dlx-block-editor-styles",
	"style": "quotes-dlx-frontend",
	"viewScript": "quotes-dlx-actions"
}Code language: JSON / JSON with Comments (json)

Where to Place Block.json

With my Block.json filled out, I needed a way to initialize it.

Most examples I’ve seen place Block.json in the src folder. I didn’t have advanced knowledge on how to get the Block.json to read in via JS and also be available for PHP use.

I ended up placing it in a public folder so that I could read it in both JS and PHP.

Registering Block.json (JS way)

So I decided to just include it in a public folder and just used that for both my JS and PHP block registration.

import metadata from '../../../../php/blocks/tweet-quotes/block.json';

registerBlockType( metadata, {
	edit: Edit,
	...
	}
);Code language: JavaScript (javascript)

The result is a bit ugly. Since I placed Block.json in a public folder, I just used the path to my publicly available Block.json file.

Registering Block.json (PHP way)

Since I do server-side rendering of my block, I had to find a way to register Block.json and also have a callback for rendering my block in PHP.

Luckily this was pretty simple:

register_block_type(
	Functions::get_plugin_dir( 'php/blocks/tweet-quotes/block.json' ),
	array(
		'render_callback' => array( $this, 'frontend' ),
	)
);Code language: PHP (php)

With register_block_type, you usually just passed in your block namespace. With Block.json, you just need to pass the path to where your Block.json is located (hence the need to place Block.json somewhere publicly).

The Benefits I Found Using Block.json

Now that I had wired up Block.json in both PHP and JS, I discovered some benefits along the way.

Here’s what I found.

Eliminate the Headache of Loading Scripts and Styles in the Right Place

One thing I learned while registering scripts and styles is that it’s a lot of trial and error to make sure they load in the appropriate place (e.g., block JS only loads in the Block Editor).

The PHP arguments for loading scripts and styles are as follows:

  • style: Loads scripts on the frontend and in the Block Editor
  • view_script: Loads scripts on the frontend for your block
  • script: Loads scripts on the frontend and the Block Editor
  • editor_script: Only loads in the Block Editor for your block
  • editor_style: Only loads in the Block Editor

I’d pass handles for each of those and use enqueue_block_editor_assets to enqueue all my scripts and styles.

add_action( 'enqueue_block_editor_assets', 'has_blocks_editor_assets' );Code language: PHP (php)

One confusing part of all this is what loads where. For example, editor_script should load only in the Block Editor. Likewise for editor_style.

There’s also a style option, which I’ve found loads your styles in the Block Editor and also on the Frontend.

I’ve found that if you only want to load a script and style only on the front-end, you can use wp_enqueue_script followed by a has_block function check.

/**
 * Register front-end scripts/styles.
 */
public function register_frontend_scripts() {
	...

	wp_register_style(
		'quotes-dlx-frontend',
		Functions::get_plugin_url( 'dist/quotes-dlx-frontend.css' ),
		$theme_deps,
		Functions::get_plugin_version(),
		'all'
	);

	if ( has_block( 'mediaron/quotes-dlx' ) ) {
		wp_enqueue_script(
			'quotes-dlx-actions',
			Functions::get_plugin_url( 'dist/quotes-dlx-actions.js' ),
			array( 'wp-i18n', 'wp-a11y' ),
			Functions::get_plugin_version(),
			true
		);
	}
	...
}Code language: PHP (php)

An Actual Schema

A schema is a strict way of telling you what you’re allowed to do. The Block.json schema is put together quite well and is a guide if you’re not sure what parameter or value you should use.

Block Icons on the WordPress Plugin Directory

If you host your block plugin on the Plugin Directory, you will see a list of blocks that your plugin has. Typically the icon is rather generic.

A generic icon for a block on the Plugin Directory.
A generic icon on the Plugin Directory

Using Block,json, you can include an SVG for your icon and it’ll show up next to your block. Unfortunately, I have yet to find a real example in the wild of this. If you’re using Block.json and have an icon, please comment below and I’ll add it to this section.

PHP and the Block Are Now One (almost)

As I began digging into Block.json, I had some expectations on how it would make initialization much easier. For example, since Block.json has attributes support, it would provide a source-of-truth for all the block attributes. This would save a lot of time by just editing Block.json instead of registering everything in both PHP and JS files.

If you use PHP to register your block along with Block.json, you can save some headaches and have one source of truth: block.json.

Before I used Block.json, I essentially had to register the block in two places.

Here’s my PHP declaration:

register_block_type(
	'has/click-to-share',
	...
);
Code language: PHP (php)

And here’s my JS initialization:

registerBlockType('has/click-to-share', {
	title: __('Highlight and Share: Click to Share', 'highlight-and-share'), // Block title.
	desription: __(
		'A block for clicking and sharing text.',
		'highlight-and-share'
	),
	...
}
Code language: JavaScript (javascript)

With Block.json, you can save a lot of repetitive code and place most of the logic in just one file.

Edit Once and Forget About It

Once Block.json is set up, you can change parameters without having to run your build script. If you want to change an attribute default or add more block support, you only have to edit Block.json.

And since Block.json (in my case) is outside the build directory, I can do quick edits without having to go into PHP to do it.

Help Other Block Developers

Since Block.json is human-readable, it’s quite easy to figure out some of the missing pieces your block entails.

Block.json Drawbacks (there aren’t many)

For the most part, if you’ve coded your block the “old” way, your block will work just fine.

While Block.json is easy in hindsight, when you’re first starting, it is a PITA to learn.

Lastly, if you’re using PHP to render your block, you still have to register the block in two places, albeit using the metadata from block.json.

Conclusion

Within this article, I laid out my journey of switching over to Block.json.

I went over:

  1. Why I decided to try out Block.json
  2. A compare/contrast how Block.json maps to existing functionality
  3. Some caveats to the Block.json API version
  4. Script and Style registration
  5. Where to place Block.json
  6. And the benefits and drawbacks

Thank you so much for reading. Please leave a comment below if you have any questions or corrections.

And for those curious…

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"title": "QuotesDLX",
	"apiVersion": 2,
	"name": "mediaron/quotes-dlx",
	"category": "text",
	"icon": "<svg width='100%' height='100%' viewBox='0 0 4450 4450' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xml:space='preserve' xmlns:serif='http://www.serif.com/' style='fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;''><g transform='matrix(4.16667,0,0,4.16667,-1325.8,-2025.45)'><path fill='#9932cc' d='M852.07,1553.89C1146.14,1553.89 1385.98,1314.05 1385.98,1020.01C1385.98,725.948 1146.14,486.109 852.07,486.109C558.033,486.109 318.193,725.948 318.193,1020.01C318.193,1314.05 558.033,1553.89 852.07,1553.89Z'/><path d='M645.766,833.41C718.162,813.992 792.571,856.965 811.989,929.362C838.72,1029.11 795.378,1186.69 610.36,1211.24C650.471,1170.11 675.614,1140.15 686.018,1100.12C624.08,1102.5 566.509,1062 549.813,999.605C530.396,927.208 573.368,852.798 645.766,833.41Z' style='fill:white;'/><path d='M988.445,833.41C1060.84,813.992 1135.28,856.965 1154.67,929.362C1181.4,1029.11 1138.09,1186.69 953.069,1211.24C993.151,1170.11 1018.29,1140.15 1028.7,1100.12C966.761,1102.5 909.188,1062 892.493,999.605C873.104,927.208 916.049,852.798 988.445,833.41Z' style='fill:white;'/></g></svg>",
	"description": "WordPress Twitter block that makes it dead simple for users to share your quotes.",
	"keywords": ["click", "tweet", "twitter", "share", "quote", "blockquote", "dlx", "quotes", "dlx", "quo"],
	"version": "1.0.0",
	"textdomain": "quotes-dlx",
	"attributes": {
		"show_copy": {
			"type": "boolean",
			"default": true
		},
		"show_permalink": {
			"type": "boolean",
			"default": true
		},
		"template": {
			"type": "string",
			"default": "light"
		},
		"button_style": {
			"type": "string",
			"default": "default"
		},
		"share_text": {
			"type": "string",
			"default": ""
		},
		"share_text_override": {
			"type": "string",
			"default": ""
		},
		"share_button_text": {
			"type": "string",
			"default": "Click to Tweet"
		},
		"share_text_override_enabled": {
			"type": "boolean",
			"default": false
		},
		"align": {
			"type": "string",
			"default": "center"
		},
		"hashtags": {
			"type": "array",
			"default": []
		},
		"twitter_username": {
			"type": "string",
			"default": ""
		},
		"maximum_width": {
			"type": "number",
			"default": 850
		},
		"maximum_width_unit": {
			"type": "string",
			"default": "px"
		},
		"rtl": {
			"type": "boolean",
			"default": false
		},
		"tweet_button_alignment": {
			"type": "string",
			"default": "right"
		},
		"tweet_icon_alignment": {
			"type": "string",
			"default": "right"
		},
		"tweet_button_enabled": {
			"type": "boolean",
			"default": true
		},
		"tweet_button_display": {
			"type": "string",
			"default": "full"
		},
		"tweet_styles_disabled": {
			"type": "boolean",
			"default": false
		},
		"anchor": {
			"type": "string",
			"default": ""
		},
		"anchor_prefix": {
			"type": "string",
			"default": "qdlx"
		},
		"has_anchor": {
			"type": "boolean",
			"default": true
		},
		"url_shortener": {
			"type": "boolean",
			"default": true
		},
		"url_shortening_service": {
			"type": "string",
			"default": "none"
		},
		"permalink": {
			"type": "string",
			"default": ""
		},
		"manualPermalink": {
			"type": "string",
			"default": ""
		},
		"enable_links_in_tweet": {
			"type": "boolean",
			"default": true
		},
		"enable_contextual_menu": {
			"type": "boolean",
			"default": true
		},
		"enable_copy_text": {
			"type": "boolean",
			"default": false
		},
		"enable_copy_tweet": {
			"type": "boolean",
			"default": true
		},
		"enable_copy_link": {
			"type": "boolean",
			"default": true
		},
		"enable_tweet_this": {
			"type": "boolean",
			"default": true
		},
		"preview": {
			"type": "boolean",
			"default": false
		},
		"blockOnly": {
			"type": "boolean",
			"default": false
		},
		"defaultsApplied": {
			"type": "boolean",
			"default": false
		},
		"transforming": {
			"type": "boolean",
			"default": false
		}
	},
	"example": {
		"attributes": {
			"preview": true,
			"blockOnly": true,
			"share_text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque malesuada dui id nisi vulputate semper. Nam sagittis ac nulla id pharetra. Maecenas congue, tellus a blandit cursus, lorem dolor hendrerit erat, sed luctus arcu velit eget ligula.",
			"template": "purple-bliss",
			"enable_contextual_menu": true,
			"enable_copy_text": true,
			"enable_copy_tweet": true,
			"enable_copy_link": true,
			"enable_tweet_this": true,
			"maximum_width": 800,
			"maximum_width_unit": "px"
		}
	},
	"supports": {
		"anchor": true,
		"align": true,
		"className": true
	},
	"editorScript": "quotes-dlx-block",
	"editorStyle": "quotes-dlx-block-editor-styles",
	"style": "quotes-dlx-frontend",
	"viewScript": "quotes-dlx-actions"
}
Code language: JSON / JSON with Comments (json)
Ronald Huereca
By: Ronald Huereca
Published On: on June 18, 2022

Ronald Huereca founded DLX Plugins in 2022 with the goal of providing deluxe plugins available for download. Find out more about DLX Plugins, check out some tutorials, and check out our plugins.

4 thoughts on “Learning Block.json – A deep dive into how Block.json Works”

  1. Very helpful, thanks for taking so much time to put this together.

    One of the downsides to using JSON seems to be the ability to have any of the values that can be filtered. For example, what if I wanted to customize one of the attributes from default true to default false? With the JSON being hardcoded, I can’t.

    Mind you, key vars / values could be setup in PHP, filterable, and then – maybe? – pass those to the JSON via an object created by WP (a la localize script). How you would get that object into that folder, I’m not sure. And would the JSON recognize it?

    Yes, the future is JS. But maybe we’re missing something by not letting PHP continue to do things JS isn’t as good at?

  2. Opps. Sorry. I was thinking that JSON was an object in some JS. But it’s a JSON file. So there’s no way to pass anything into it. Maybe there’s a hook in WP that allows for customization of the “default” block.json?

    1. What I did was use wp_localize_script and spread out defaults into the block itself.

      You just have to make sure the defaults match your attributes one-to-one to do this.

      setAttributes( { ...defaults } );

Leave Your Valuable Feedback

Your email address will not be published. Required fields are marked *

Shopping Cart
  • Your cart is empty.
Scroll to Top