Roots Discourse

Sage 10 Custom Gutenberg Blocks best practice

Hi there,

I have been using the full Roots stack for quit some time now and I am currently exploring the functionalities of Sage 10 and we’re slowly trying to move all our design blocks to the gutenberg editor.

So I know by now how to add custom Gutenberg blocks using the awesome acf-composer library and how to enqueue assets for each block using the enqueue_style and enqueue_script hooks: https://www.advancedcustomfields.com/resources/acf_register_block_type/#parameters

I also understand that you need to use the @tinypixelco/laravel-mix-wp-blocks package in order to use WordPress block scripts in the editor.js file.

But what if I want to create a custom Gutenberg block myself using Wordpress core blocks with for example Innerblocks? I followed this guide: https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/writing-your-first-block-type/ and registered my own block like this:

/*
 * Register Custom Gutenberg Blocks
 */
function registerBlocks() {
	wp_register_script(
		'ua/custom-block-editor',
		asset('scripts/blocks/custom-block-editor.js')->uri(),
		['sage/vendor.js'],
		false,
		true
	);

	register_block_type(
		'ua/custom-block', [
			'api_version'   => 2,
			'style'         => 'ua/custom-block',
			'editor_script' => 'ua/custom-block-editor'
		]
	);
}
add_action('init', 'registerBlocks');

In my resources/assets/scripts/blocks/custom-block-editor.js:

import { registerBlockType } from '@wordpress/blocks';
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';

const blockColumn = [
	'core/column', {
		verticalAlignment: 'bottom'
	}, [
		['core/cover', {
			contentPosition: 'bottom left',
			dimRatio: 0
		}, [
			['core/heading', {
				level: 2,
				placeholder: 'Titel toevoegen'
			}],
			['core/button', {
				palceholder: 'Link toevoegen',
				backgroundColor: 'primary',
				textColor: 'white'
			}]
		]]
	]
];

const blockTemplate = [
	['core/columns', {}, [
		blockColumn,
		blockColumn
	]]
];

registerBlockType('ua/custom-block', {
	apiVersion: 2,
	title: 'My Custom Block',
	icon: 'columns',
	category: 'design',
	example: {},
	edit() {
		const blockProps = useBlockProps();

		return (
			<div { ...blockProps }>
				<InnerBlocks
					template={blockTemplate}
					templateLock="all"
				/>
			</div>
		);
	},
	save() {
		const blockProps = useBlockProps.save();

		return (
			<div { ...blockProps }>
				<InnerBlocks.Content/>
			</div>
		);
	},
});

My custom block works fine!
However, I am wondering what the best practice is for registering these blocks in combination with laravel mix and laravel-mix-wp-blocks?

Right now I added a new entry for my block like this:

mix
	.js('resources/assets/scripts/app.js', 'scripts')
	.js('resources/assets/scripts/customizer.js', 'scripts')
	.blocks('resources/assets/scripts/editor.js', 'scripts')
	.blocks('resources/assets/scripts/blocks/custom-block-editor.js', 'scripts/blocks')
	.autoload({ jquery: ['$', 'window.jQuery'] })
	.extract();

Although according to the docs you’re supposed to use mix.block(), it does compile correctly?

But when running a yarn build, I get this error:

Asset [/srv/www/example.com/current/web/app/themes/sage/public/scripts/manifest.asset.php] not found.

There is a manifest.asset.php file in the scripts/blocks folder, but not in the scripts root. When I remove the second blocks entry, the manifest.asset.php file is in the scripts root.

So my question is, what is best practice for registering my own blocks?

Should they be added in the main editor.js file and import the partials from there and set the editor_script to the main sage/editor.js?

I thought the assets should only be enqueued when the block is actually used on a page? So it would make sense to have separate assets for them right?

Or should the output of the mix.blocks always be the same folder?

I would love to get some input on this!
Thanks!