I am trying to create a plugin that will have multiple blocks and an admin page. Everything seems to be working fine. The admin page is showing up, the blocks are working as well. But I am getting an error in the console when I get to the Gutenberg editor and that is making me worried if what I did is wrong or not.
This is the error:
'Block "my-plugin/block-1" is already registered'
'Block "my-plugin/block-2" is already registered'
This is the plugin php file:
class MY_PLUGIN{
public function __construct() {
add_action( 'admin_menu', [ $this, 'menu_item' ] );
add_action( 'admin_enqueue_scripts', [ $this, 'load_custom_wp_admin_scripts' ] );
add_action( 'init', [ $this, 'register_blocks' ] );
}
/**
* Initialize the plugin
*/
public static function init(){
static $instance = false;
if( !$instance ) {
$instance = new self();
}
return $instance;
}
/**
* Create a new admin page for our app.
*/
public function menu_item() {
add_menu_page(
'My Plugin',
'My Plugin',
'manage_options',
'my-plugin',
[ $this, 'dashboard_page' ],
'dashicons-schedule',
3
);
}
/**
* Admin page markup.
*/
public function dashboard_page() {
echo '
<h2>Pages</h2>
<div id="my-plugin"></div>
';
}
/**
* Load admin scripts and stylesheets
*/
public function load_custom_wp_admin_scripts( $hook ) {
// Load only on ?page=my-plugin
if ( 'toplevel_page_my-plugin' !== $hook ) {
return;
}
// Load the required WordPress packages.
// Automatically load imported dependencies and assets version.
$asset_file = include plugin_dir_path( __FILE__ ) . 'build/index.asset.php';
// Enqueue CSS dependencies.
foreach ( $asset_file['dependencies'] as $style ) {
wp_enqueue_style( $style );
}
// Load our app.js.
wp_register_script(
'my-plugin',
plugins_url( 'build/index.js', __FILE__ ),
$asset_file['dependencies'],
$asset_file['version']
);
wp_enqueue_script( 'my-plugin' );
// Load our style.css.
wp_register_style(
'my-plugin',
plugins_url( 'src/admin/stylesheet/style.css', __FILE__ ),
array(),
$asset_file['version']
);
wp_enqueue_style( 'my-plugin' );
}
public function register_blocks() {
register_block_type( __DIR__ . '/build/blocks/block-1' );
register_block_type( __DIR__ . '/build/blocks/block-2' );
}
}
Each block's index.js file looks like this:
import { registerBlockType } from '@wordpress/blocks';
import './style.scss';
import './editor.scss';
import Edit from './edit';
import Save from './save';
import metadata from './block.json';
/**
* Every block starts by registering a new block type definition.
*/
registerBlockType( metadata, {
edit: Edit,
save: Save,
} );
Am I doing anything wrong here?
UPDATE* Here's how block.json looks like. Both block's the same except name and title is different in each. Like block-1 and block-2:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "my-plugin/block-1",
"version": "0.1.0",
"title": "Block 1",
"category": "text",
"icon": "flag",
"description": "Some description",
"attributes": {
"message": {
"type": "string",
"source": "text",
"selector": "div"
}
},
"supports": {
"html": false
},
"textdomain": "block-1",
"editorScript": "file:../../index.js",
"editorStyle": "file:../../index.css",
"style": "file:../../style-index.css"
}
FOLDER STRUCTURE:
Admin Index.js:
import { render } from '@wordpress/element';
import App from './components/App/App';
window.addEventListener(
'load',
function () {
render(
<App />,
document.querySelector( '#my-plugin' )
);
},
false
);
UPDATE:
Getting these errors in admin side and blocks are missing after adding custom webpack file as suggested by S.Walsh.
UPDATE:
After implementing S.Walsh's suggestions, the blocks were working fine but admin page was not showing any components. So I updated load_custom_wp_admin_scripts
function to build path for the register script:
public function load_custom_wp_admin_scripts($hook) {
if ('toplevel_page_my-plugin' !== $hook) {
return;
}
$asset_file = include plugin_dir_path(__FILE__) .'build/admin/index.asset.php';
foreach ( $asset_file['dependencies'] as $style ) {
wp_enqueue_style( $style );
}
wp_register_script('my-plugin', plugins_url('build/admin/index.js', __FILE__), $asset_file['dependencies'], $asset_file['version']);
wp_enqueue_script('my-plugin');
wp_register_style('my-plugin', plugins_url('src/admin/stylesheet/style.css', __FILE__), array(), $asset_file['version']);
wp_enqueue_style('my-plugin');
}
The components are showing up now but the stylesheet in not taking any effect.
UPDATE:
For the admin styles to take effect, the css file should be changed to scss. And also update it in load_custom_wp_admin_scripts
function. I also removed view.js files as it is not needed.
The error is triggered in plugin.php by the function load_custom_wp_admin_scripts()
as:
The file src/index.js
contains code to register the blocks on the admin_enqueue_scripts hooks in load_custom_wp_admin_scripts()
.
The blocks are also registered via the register_blocks()
function using each blocks block.json
on the init hook.
When you visit your custom Admin page, the admin_enqueue_scripts
and init
hook both attempt to register the blocks, creating the error.
Your screenshot shows that the script entry point is compiling all the assets into index.asset.php
hence your blocks build directories only contains the block.json
files without their assets.
The best practise is to keep the block code independent of any other plugin JavaScript, for this kind of project setup, you can define multiple entry points to build the required assets.
Solution
Let's set up a basic plugin project with multiple blocks from the start to explore an alternative approach:
1. Project Setup via command line with @wordpress/create-block:
# 1. Create "my-plugin" and install required files
npx @wordpress/create-block@latest my-plugin
# 2. Remove the default src directory that contains the default single block
rmdir /s my-plugin\src
# 3. Make a new src\blocks directory and enter it
mkdir my-plugin\src\blocks && cd my-plugin\src\blocks
# 4. Use create block to scaffold new blocks as required with --no-plugin option
npx @wordpress/create-block@latest --no-plugin block-1
npx @wordpress/create-block@latest --no-plugin block-2
# 5. Run build
cd [path-to]\my-plugin
npm run build
Update the create_block_my_plugin_block_init()
function to register both blocks:
my-plugin.php
function create_block_my_plugin_block_init() {
register_block_type( __DIR__ . '/build/blocks/block-1' );
register_block_type( __DIR__ . '/build/blocks/block-2' );
}
add_action( 'init', 'create_block_my_plugin_block_init' );
Test the plugin from the Editor to see both block-1
and block-2
load without error.
At this stage, you have a solid foundation for a basic plugin with two working blocks, properly compiled with their assets.
The next steps are optional to extend the plugin with an Admin page.
2. Admin Page Setup
The src/admin/
directory will contain a index.js
script which imports the stylesheet/style.scss
as its required for build process. The index.js
does not load any blocks.
src/admin/index.js
import './stylesheet/style.scss';
...
// Other code for Admin Page..
3. Build Setup
Create a new custom webpack.config.js
to enable additional entry points for your project to build all required assets:
[my-plugin]/webpack.config.js
const defaultConfig = require('@wordpress/scripts/config/webpack.config');
module.exports = {
...defaultConfig,
entry: {
'admin/index': './src/admin/',
'blocks/block-1/index': './src/blocks/block-1/',
'blocks/block-2/index': './src/blocks/block-2/'
},
};
4. Updates to Main Plugin File
Next, update my-plugin.php
to include your original class MY_PLUGIN
code with the following update to load_custom_wp_admin_scripts()
:
my-plugin.php
class MY_PLUGIN
{
...
/**
* Load admin scripts and stylesheets
*/
public function load_custom_wp_admin_scripts($hook)
{
// Load only on ?page=my-plugin
if ('toplevel_page_my-plugin' !== $hook) {
return;
}
// Register and load admin script with dependancies
$asset_file = include plugin_dir_path(__FILE__) . 'build/admin/index.asset.php';
wp_register_script('my-plugin-admin', plugins_url('build/admin/index.js', __FILE__), $asset_file['dependencies'], $asset_file['version']);
wp_enqueue_script('my-plugin-admin');
// Register and load admin style.css.
$admin_style = plugins_url('build/admin/style-index.css', __FILE__);
wp_register_style('my-plugin-admin-style', $admin_style, array(), '1.0'); // check
wp_enqueue_style('my-plugin-admin-style');
}
...
}
Check that all the file paths are correct then rebuild your project. The build directory for each block now only contains that blocks assets; the script and style assets in for the Admin page are output to build\admin\
.
Example Project Directory Setup
Now you can go on and create as many new blocks as you like!
Additional Notes The errors shown in the updated question screenshot indicate that:
Both are resolved by either adding the missing files or updating their declarations in block.json
to correct path/filename for your project, eg:
"editorScript": "file:./index.js",
"viewScript": "file:./view.js"
Ensure you rebuild the project and clear browser cache before testing again.