Block.json received a small upgrade with WordPress 6.3, which upped the version of the API to version 3 (v3).
So what does this entail, why should you care about it, and what can plugin and theme developers do with the new API version?
What is Block.json Version 3?
Version 3, as of this writing, enables an iframe to wrap around block content in the site and block editor. This separates the content area from admin styles, avoiding conflicts and style clashes. If version 3 is enabled, the block content will be neatly wrapped in an iframe, allowing theme and plugin authors a way to hook in and add their own customizations. This is particularly useful for theme developers who have long wished to be able to have better styling control in the block editor.
The block.json
file only comes into play for block developers. This is a version flag, so think of this as a “go” or “no go” panel of lights for all blocks. If all blocks have opted-in, version 3 should be auto-enabled assuming there’s no custom field trickery.
How do you opt-in to Block.json and v3?
It’s an incredibly frustrating experience <sarcasm>. All you have to do is change your Block.json’s API version to 3. It looks like this:
That’s right. Changing from version 2 to 3 is as simple as changing the version number for the apiVersion
parameter.
What changes with version 3?
I’ll start with a quoted summary:
The goal of version 3 is to load the post editor and site editor inside an iframe. Why an iframe? Please let me explain.
If you’ve ever tried to style in the block editor, you’ll notice that the mobile and tablet previews are rendered in an iframe. This makes styling inside of an iframe possible, but not without hacks. We’ll be using two WordPress functions: wp_deregister_script
and wp_register_script
.
Here’s the hacky code we used to load styles in the iframe.
function dlx_add_block_stylesheets() {
// Register the main block style file.
wp_register_style(
'dlx_block_styles',
asset_path( 'wp_blocks.css' ),
array(),
dlx_SCRIPT_VERSION,
'all'
);
// Check to see if we need to inject styles into the preview modes.
$inject_styles = false;
// This is to check the file exists.
if ( file_exists( ABSPATH . WPINC . '/css/dist/block-editor/style.min.css') ) {
$inject_styles = true;
}
// If file exists, deregister core style so we can latch onto it.
if ( $inject_styles ) {
wp_deregister_style( 'wp-block-editor' );
// Re-register style with our theme block styles as a dependency.
wp_register_style(
'wp-block-editor',
esc_url( home_url( 'wp-includes/css/dist/block-editor/style.min.css' ) ),
array( 'dlx_block_styles' )
);
}
}
add_action( 'enqueue_block_editor_assets', 'dlx_add_block_stylesheets' );
Code language: PHP (php)
Did I mention hacks? We’ve latched on to an existing style that loads in the iframe. First, we register our custom block styles using wp_register_style
. After that, we check for the existence of the stylesheet we want to latch onto. Lastly, we used wp_deregister_style
to remove the core stylesheet and then re-register it with our styles as a dependency. WordPress will load its block editor stylesheet; when it does, we simply latch onto it as a dependency.
For this next hack, we needed to inject inline styles inside the iframe:
import Sidebar from "./sidebar";
const { registerPlugin } = wp.plugins;
const { PluginSidebar, PluginSidebarMoreMenuItem } = wp.editPost;
const { select } = wp.data;
let stylesIntroduced = false;
registerPlugin("landing-page-gutenberg-template", {
icon: (
<svg>
{ /* code here */ }
</svg>>
),
render: () => {
// We're piggy backing off a render method here and getting the style settings, adding to it, and updating the core store settings.
const settingStyles = select( 'core/block-editor' ).getSettings().styles; // This gets the current styles.
if ( settingStyles && ! stylesIntroduced ) {
// Add to the settingStyles array.
settingStyles.push( {
css: 'table { margin-bottom: 1.5rem; color: #5e5e5e; } th, td { font-family: "Poppins", "Poppins", -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; font-feature-settings: \'kern\', \'liga\', \'ss01\', \'ss02\';padding: 1rem; vertical-align: top; border-top: 1px solid #e6e6e6; }',
} )
// Update the settings.
wp.data.dispatch('core/block-editor').updateSettings( { styles: settingStyles } );
// Make sure we only do it once.
stylesIntroduced = true;
}
return null;
},
});
Code language: JavaScript (javascript)
This code runs in the render
argument, which is used to do output to the screen. While in render
, we get the block editor styles and add some inline CSS. Finally, we update the core styles.
So why am I showing you all this? Because the iframes make it incredibly difficult to style content in the block editor.
The issue with iframes
The issue with iframes is that they are essentially designed to be independent of the content it is in. Sure, we can style the iframe itself, but styling the contents within the iframe isn’t possible unless there is some way to hook into the iframe output. Easier said than done.
But iframes are here to say, and here’s why: its weakness as basically an independent element is also what makes iframes so great.
Why iframes are needed in the post and site editor
Since the content of the block editor will be wrapped in an iframe, it’s independent of any admin style. In reverse, people loading scripts and styles in the block editor won’t affect the content unless explicitly added.
I encourage you to read about the rational behind iframes, as it is explained rather well in the linked article. It’s a bit of an older article, but many valid points resonate even today.
Another point is that the responsive previews are more accurate as they can represent screensizes without many workarounds.
So, to recap, iframes are beneficial because:
- They’re style-independent.
- They’re easier to manipulate and more responsive when it comes to simulating breakpoints.
- Block and theme authors can customize the block editor content appearance without affecting the rest of the block content.
- It results in far fewer script and style conflicts.
So, with version 3, how do we get our scripts and styles in the iframe?
Here’s a quick caveat: unless all block plugins on a site have opted-in to version 3, there is no iframe to worry about. So if you’re the holdout still rocking version 2, you don’t have to worry about the iframe until you switch to version 3 (and everyone else has too).
That being said, the common hook enqueue_block_editor_assets
is not going away anytime soon.
I tried doing what was suggested to enable the iframe in the post editor. I removed all plugins, enabled the Twenty Twenty Three theme, and changed one activated block plugin to using version 3 of the Block.json API. While I noticed no new iframe in the post editor, I did see it in use in the site editor.
As I learned throughout my research, I decided to take a stab at loading my scripts and styles inside the iframe in the site editor.
The rest of this tutorial will explain the hooks you’ll see when loading scripts and styles for the block editor, particularly in themes.
enqueue_block_editor_assets vs enqueue_block_assets
As of WordPress version 6.3, you can use enqueue_block_assets to load your scripts in the iframe. Enqueue_block_assets will load your scripts and styles in the block editor and inside the iframe for backward compatibility purposes. Prior to WordPress 6.3, enqueue_block_assets
was not able to load anything in an iframe.
It is now recommended to stop using enqueue_block_editor_assets
and use enqueue_block_assets
instead. This, of course, assumes post-6.3 development.
What about previous versions like WordPress 6.2? Or how would someone support an older version and the newest version that encourages all block developers to opt-in to version 3?
So, for 6.3 and above, enqueue_block_assets
will load on the frontend and in the iframe (if iframe wrapping is enabled). Pre 6.3 enqueue_block_assets
was primarily used to enqueue assets needed for the block editor (and the frontend).
A question posted on GitHub brings up a good point. Why would we use enqueue_block_assets
if the scripts and styles are also loaded in the frontend? Simply put, you can easily wrap an is_admin
in your enqueue_block_assets
action to prevent any frontend loading.
Here’s an example I “borrowed” from GitHub to demonstrate only iframe loading (note the is_admin
check):
/**
* Enqueue content assets but only in the Editor.
*/
function example_enqueue_editor_content_assets() {
if ( is_admin() ) {
wp_enqueue_script(
'example-editor-content-scripts',
plugins_url( 'constent-scripts.css', __FILE__ ) );
}
wp_enqueue_style(
'example-editor-content-styles',
plugins_url( 'constent-styles.css', __FILE__ ) );
}
}
}
add_action( 'enqueue_block_assets, 'example_enqueue_editor_content_assets' );
Code language: PHP (php)
How can I use enqueue_block_assets for older versions of WordPress
Do I have a hack for you? I’m using a class-based structure for this example, but it should work if you change the methods to functions and prefix them appropriately.
This first code sample uses the init
action to start things off:
public static function run() {
$self = new self();
add_action( 'init', array( $self, 'init' ) );
return $self;
}
Code language: PHP (php)
This is what I refer to as a class runner. I usually call it when the plugins_loaded
action is fired.
From there, let’s move into the init
callback (I left some rational in the comments):
public function init() {
// Enqueue block assets.
add_action( 'enqueue_block_editor_assets', array( $this, 'register_block_editor_scripts' ) ); // This enqueue's like normal.
add_action( 'enqueue_block_assets', array( $this, 'action_enqueue_block_assets' ) );
// Since 6.3, enqueue_block_assets runs in an iframe in the site editor. In 6.3,
// enqueue_block_editor_assets loads outside of editor iframe. Thus, you can check
// if any of your enqueued script have been registered, and if not,
// you're on 6.3 and you can enqueue them here. Otherwise, you're on a
// pre-6.3 version.
}
Code language: PHP (php)
You’ll notice I’m using both enqueue_block_editor_assets
and enqueue_block_assets
together. Why would I do this?
enqueue_block_editor_assets
still works well for pre-6.3.enqueue_block_assets
loads first from my tests, both on the frontend and the site editor.
As one contributor mentioned on GitHub:
enqueue_block_assets
should be used to load editor stylesheets and scripts. Please noteenqueue_block_assets
can run on the frontend if there is nois_admin
check.enqueue_block_editor_assets
should include scripts and styles that can run in the block editor, but not affect any content styles.- If using
enqueue_block_editor_assets
, you’ll want to prefix your CSS with:.editor-styles-wrapper
or.wp-block*
. This is to prevent style leakage.
Let’s move on to the rest of the code:
/**
* Enqueue block assets inside an iframe.
*/
public function enqueue_block_editor_iframe() {
if ( ! is_admin() ) {
return;
}
// We'll pick on a script that's enqueued using `enqueue_block_editor_assets`.
if ( wp_script_is( 'alerts-dlx-block', 'enqueued' ) ) {
// If this script was enqueued, it means `enqueue_block_editor_assets` has run, therefore we are not in an iframe.
// If the script is not enqueued, we're likely in the iframe, so we can enqueue or assets as normal.
return;
}
// Register styles for the iframe in 6.3.
wp_enqueue_style(
'alerts-dlx-block-editor',
Functions::get_plugin_url( 'dist/alerts-dlx-block-editor.css' ),
array(),
Functions::get_plugin_version(),
'all'
);
wp_enqueue_style(
'alerts-dlx-block-editor-styles',
Functions::get_plugin_url( 'build/alerts-dlx.css' ),
array( 'alerts-dlx-block-editor' ),
Functions::get_plugin_version(),
'all'
);
}
/**
* Enqueue scripts for the block editor.
*/
public function enqueue_block_editor_scripts_styles() {
// Enqueue scripts and styles that need to go in the iframe.
wp_enqueue_style(
'alerts-dlx-block-editor',
Functions::get_plugin_url( 'dist/alerts-dlx-block-editor.css' ),
array(),
Functions::get_plugin_version(),
'all'
);
wp_enqueue_style(
'alerts-dlx-block-editor-styles',
Functions::get_plugin_url( 'build/alerts-dlx.css' ),
array( 'alerts-dlx-block-editor' ),
Functions::get_plugin_version(),
'all'
);
wp_enqueue_style(
'alerts-dlx-block-editor-styles-lato',
Functions::get_plugin_url( 'dist/alerts-dlx-gfont-lato.css' ),
array(),
Functions::get_plugin_version(),
'all'
);
wp_enqueue_style(
'alerts-dlx-common',
Functions::get_plugin_url( 'dist/alerts-dlx-common.css' ),
array( 'alerts-dlx-block-editor-styles-lato' ),
Functions::get_plugin_version(),
'all'
);
wp_enqueue_script(
'alerts-dlx-block',
Functions::get_plugin_url( 'build/alerts-dlx.js' ),
array(),
Functions::get_plugin_version(),
true
);
wp_localize_script(
'alerts-dlx-block',
'alertsDlxBlock',
array(
'font_stylesheet' => Functions::get_plugin_url( 'dist/alerts-dlx-gfont-lato.css' ),
)
);
}
Code language: PHP (php)
I’ve created a nifty flowchart to demonstrate what’s happening:
The theory behind this is that enqueue_block_assets
loads first, so it has a chance to register its scripts. After that, enqueue_block_editor_assets
is run, which registers its scripts/styles.
When in an iframe, enqueue_block_editor_assets
is not run. The only thing that should be called in an iframe is enqueue_block_assets
. So a simple handle check will eliminate any redunancy, and set you up for iframes in the site editor and the block editor in the future when iframes apply to the post content block editor.
What’s the status of being able to add iframe’d content?
As mentioned, all blocks on the site must have opted-in to version 3 in Block.json. I attempted this locally with 6.3, with one block opted-in, and I used enqueue_block_assets
to enqueue my scripts.
No matter how I tried, I couldn’t get an iframe to load in the post editor, but I could add my styles to the site editor’s iframe. This leads me to conclude that either the block editor isn’t ready for iframes yet, or I’m doing something wrong (not out of the question).
Conclusion
Getting scripts and styles into the post editor iframe is coming, but not until all block plugins on a site have opted-in to version 3 in Block.json. This could take a while for mass adoption.
Switching to version 3 is simple. It’s just a single flag. However, the caveats, backward compatibility, and the amount of community opt-in will certainly make this change rather ambitious but worthwhile.
That being said, what do you think of this API change? Are you excited to finally be able to load assets in the content iframe? Please let me know in the comments.
Like this tutorial? There's more like it. Subscribe today!
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.