Assets loading in WordPress block
There are various ways to register blocks, but using block.json is highly recommended by WordPress. The block.json
metadata file is also capable of loading default scripts and styles.
However, there are cases when block’s assets need to be loaded conditionally.
Default scripts and styles
I like to use @wordpress/create-block for block development in WordPress as it provides a simplified, structured starting point for creating blocks. The package generates various types of files for a block, including the block.json
file.
The block.json
metadata file offers parameters to manage scripts and styles both on the front-end (what visitors see) and back-end (where you edit content).
Metadata parameters
- The
editorScript
parameter specifies the location of a script file or an enqueue handle for loading scripts in the Block Editor (back-end). - The
script
parameter specifies the location of a script file or an enqueue handle needed for both the front-end and back-end. - The
viewScript
parameter is for scripts to load on the front-end. It accepts a file location or an enqueue handle. - The
editorStyle
parameter specifies the location of a stylesheet or an enqueue handle for styling in the Block Editor (back-end). - The
style
parameter indicates the location of styles needed for both the front-end and back-end, or an enqueue handle.
Note, each parameter can accept an array, allowing to specify multiple file locations and/or script handles.
Load default scripts and styles via path
One way to load block assets is by specifying a path in the block.json
file.
For the Flip Block plugin, I developed two complementary blocks. Each block includes default assets specified in the block.json
file. Below is a segment code from the metadata file of the Card block:
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css"
In this snippet, three assets are being specified: editorScript
, editorStyle
, and style
. Here's a breakdown of each line in the code snippet:
- The 1st line specifies the JavaScript file (
index.js
) that will be loaded in the Block Editor (back-end) whenever the Card block is being used or edited. Thefile:
protocol signifies thatindex.js
is a file located in the same directory as theblock.json
file. - The 2nd line specifies the CSS stylesheet (
index.css
) that will be applied in the Block Editor (back-end) to style the Card block during editing. Similar toeditorScript
, thefile:
protocol signifies thatindex.css
is a file located in the same directory as theblock.json
file. - The 3rd line specifies the CSS stylesheet (
style-index.css
) that will be applied both in the Block Editor (back-end) and on the front-end of the website to style the Card block. This stylesheet is loaded in both environments, ensuring consistent styling whether you're editing the block or viewing it on the live site.
It's important to note that the files referenced in this block.json
snippet are located in the build
folder, not the src
folder.
During the build process, source files from the src
folder are compiled and output to the build
folder. For instance, editor.scss
from the src
folder would be compiled into index.css
in the build
folder.
Load scripts and styles via handles
There are cases when “path” approach can cause issues. In that case, “handle” approach is recommended to avoid the issues.
To load scripts and styles using handles, utilize the functions wp_register_script
and wp_register_style
in PHP file:
/**
* Registers a script for a block.
*
* The 'wp_register_script' function is used to register a script with WordPress,
* which can later be enqueued for use on the front-end or back-end of the site.
*
* @see https://developer.wordpress.org/reference/functions/wp_register_script/
*
* @param string $handle A unique name for the script used to identify it.
* @param string $src The URL to the script file.
* @param array $dependencies Optional. An array of registered script handles this script depends on.
* @param bool $in_footer Optional. Whether to enqueue the script before </body> instead of in the <head>.
*/
wp_register_script(
'my-block-script',
plugins_url( '/build/index.js', __FILE__ ),
array( 'wp-blocks', 'wp-element', 'wp-editor' ),
true
);
/**
* Registers an editor style for a block.
*
* The 'wp_register_style' function is used to register a stylesheet with WordPress,
* which can later be enqueued for use in the Block Editor.
*
* @see https://developer.wordpress.org/reference/functions/wp_register_style/
*
* @param string $handle A unique name for the stylesheet used to identify it.
* @param string $src The URL to the stylesheet file.
* @param array $dependencies Optional. An array of registered stylesheet handles this stylesheet depends on.
* @param string $version Optional. String specifying the stylesheet version number.
*/
wp_register_style(
'my-block-editor-style',
plugins_url( '/build/index.css', __FILE__ ),
array(),
'1.0.0'
);
/**
* Registers styles for both the front-end and back-end of a block.
*/
wp_register_style(
'my-block-style',
plugins_url( '/build/style-index.css', __FILE__ ),
array(),
'1.0.2'
);
After registering the handles, incorporate them into block.json
file as follows:
"editorScript": "my-block-script",
"editorStyle": "my-block-editor-style",
"style": "my-block-style"
In this snippet, the editorScript
, editorStyle
, and style
fields are using handles instead of file paths. These handles are identifiers that have been previously defined in PHP using the wp_register_script
and wp_register_style
functions.
Conditionally load block assets
The “handle” approach for loading scripts and styles is also used when there is a need to conditionally load scripts and styles for a WordPress block.
Use case example
When working on an update for the Sortable Block plugin, I came across a need to load a JavaScript file only under a certain condition.
The block has an option allowing users to select a filter date, which is optional. Upon selecting a date, a specific JavaScript file needs to be loaded on the front-end. This script is responsible for checking child elements to determine if they have expired based on the selected date.
However, if the filter date is not selected, there's no need to load this script as it would remain unused, adding unnecessary load to the page.
Solution
To load the JavaScript file, or CSS stylesheet, only when the specific block option is set, it's essential to check the block's attributes. The check for the attribute value needs to happen during the block rendering process.
There are two ways to access the render process.
The original method is to use the render_callback
argument when register_block_type
. The alternate method, which has been supported since WordPress 6.1, is to use the render property in block.json
.
Personally, I prefer the original method:
/**
* Register the Sortable block.
*
* This code snippet demonstrates how to register a new block type in WordPress.
* The 'register_block_type' function is used, with the path to the block's files
* and a custom render callback function specified as arguments.
*
* @see https://developer.wordpress.org/reference/functions/register_block_type/
*/
register_block_type(
__DIR__ . '/build/container',
array(
'render_callback' => 'sortable_render_block_sortable_container',
)
);
The code snippet above is from the Sortable Block plugin and demonstrates how to register a block in WordPress using the register_block_type
function.
There is an array containing a key render_callback
, which specifies a custom render callback function sortable_render_block_sortable_container
to be used when rendering the block on the front-end.
The render callback function serves as the place to inspect the block's saved options and execute conditional loading of styles and scripts.
However, it's important to have these styles and scripts registered beforehand (as discussed earlier in the section about using handles) before using them in the render function.
/**
* Render callback function for the Sortable Container block.
*
* This function checks if a specific attribute ('displayType') is set to 'date',
* and if so, it enqueues a necessary JavaScript script to handle date-related functionalities.
* The script is enqueued only if it hasn't been enqueued already, ensuring efficiency.
*
* @param array $attributes The block attributes.
* @param string $content The block content.
*
* @return string Returns the original block content, unmodified.
*/
function sortable_render_block_sortable_container( $attributes, $content ) {
// Check if 'displayType' is set to 'date' in the block's attributes.
if ( isset( $attributes['filter']['displayType'] ) && 'date' === $attributes['filter']['displayType'] ) {
// Check if 'sortable-block-core-script' is not already enqueued.
if ( ! wp_script_is( 'sortable-block-core-script', 'enqueued' ) ) {
// Enqueue 'sortable-block-core-script' if the conditions are met.
wp_enqueue_script( 'sortable-block-core-script' );
}
}
// Return the original block content unmodified.
return $content;
}
The code snippet above defines a render callback function for a WordPress block. This function is triggered when the block is being rendered on the front-end. The render function takes two parameters: $attributes
and $content
.
- It checks if a particular attribute (
displayType
) is set to 'date' within the block's settings. - If 'date' is the selected
displayType
, it then checks whether a script with the handle'sortable-block-core-script'
has already been enqueued. - If the script hasn't been enqueued, it enqueues the script using the
wp_enqueue_script
function. - Finally, the function returns the original block content unmodified, ensuring the block is displayed as intended on the front-end.
This setup allows for the conditional loading of a script based on the block's attribute settings, optimizing the load only when necessary.