# Register block methods & how to enqueue block assets?

**URL:** https://discourse.roots.io/t/register-block-methods-how-to-enqueue-block-assets/27058
**Category:** sage
**Tags:** gutenberg, bud, sage10
**Created:** 2024-04-26T08:01:04Z
**Posts:** 9

## Post 1 by @Twansparant — 2024-04-26T08:01:04Z

Hi there,

I’m struggling a bit what in 2024 the best method is to register a **custom Gutenberg block**. You’ve got quite a few options these days;

**Bud**  
[roots.register.blocks](https://bud.js.org/extensions/bud-preset-wordpress/editor-integration/blocks)

**JS**  
[registerblocktype](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/#registerblocktype)

**ACF Composer**  
[`wp acorn acf:block Example`](https://github.com/Log1x/acf-composer?tab=readme-ov-file#generating-a-block)

**PHP**  
[register\_block\_type](https://developer.wordpress.org/reference/functions/register_block_type/)

I’ve been reading the [Block Editor Development with HMR Support](https://roots.io/block-editor-development-with-hmr-support/#block-editor-development-setup) article and am wondering how other people handle individual block styling when they move their blocks to a **Clover** plugin?

What if these blocks are part of the overall theme design and you want to use the same style config (tailwind config / bootstrap variables) in these blocks?

I like the Bud method of registering blocks, filters etc. so I would like to use this approach in my new project. The only thing I’m still struggling with is how to enqueue indivdual block assets? Let’s say I have a carousel block using [Swiper](https://swiperjs.com/) and I want to enqueue a separate js & css file only when this block is being used on a page:

```
/* Block name */
export const name = `sage/swiper`

/* Block title */
export const title = `Swiper block`

/* Block category */
export const category = `widgets`

/* Block edit */
export const edit = () => <></>

/* Block save */
export const save = () => <></>
```

I used to do this like this for JS blocks:

```
function register_blocks() {
	wp_register_script(
		'sage/swiper-editor',
		asset('scripts/swiper.editor.js')->uri(),
		['ua/vendor.js']
	);

	wp_register_style(
		'sage/swiper',
		asset('styles/swiper.css')->uri()
	);

	register_block_type(
		'sage/swiper', [
			'api_version' => 2,
			'editor_script' => 'sage/swiper-editor',
			'editor_style' => 'sage/swiper',
			'render_callback' => function($block_attributes, $content) {
				wp_enqueue_style('sage/swiper');
				return $content;
			}
		]
	);
}
add_action('init', 'register_blocks);
```

or for ACF blocks:

```
namespace App\Blocks;

use Log1x\AcfComposer\Block;
use StoutLogic\AcfBuilder\FieldsBuilder;
use function Roots\bundle;

class Swiper extends Block
{
	....
	public function enqueue() {
		bundle('swiper')->enqueue();
	}
```

But that meant [adding every individual block assets to the bud config entries](https://discourse.roots.io/t/bud-config-for-outputting-multiple-css-files-from-scss-for-acf-blocks/22498).  
Is there a way to enqueue these assets automatically with **Sage** , **[Poet](https://github.com/Log1x/poet)** or **Bud** without having to list them separately in the config?

Or what is the best way to do this?  
Are you just adding these assets to your main `app.css` and `app.js`? I thought it was best practice to enqueue these only when a block is added?

Any tips are welcome, thanks!

---

## Post 2 by @slowrush — 2024-04-26T08:39:08Z

Hey @Twansparant, I think [dynamic imports](https://bud.js.org/learn/modules/js-modules#dynamic-imports) solves asset loading for all of these scenarios.

Personally I’m still outputting multiple files and importing them in ACF Blocks. We had a few issues with dynamic imports + dev server, but that was a _looong_ time ago so I’m pretty sure that’s all resolved now.

There are a few posts with ref to dynamic imports in discourse + discord if need examples. But this [Slider example in the Bud docs](https://bud.js.org/learn/modules/js-modules#conditional-css) is pretty solid.

---

## Post 3 by @slowrush — 2024-04-26T09:21:07Z

As for registering custom Gutenberg blocks, all those methods are great, but vary slightly in implementation/needs.

I guess it comes down to:

- If you want the full Gutenberg experience, JS/Bud is the way to go
- If you prefer working with ACF Blocks, go with ACF Composer

But I’m sure others might have different thoughts, looking forward to hearing them :slight_smile:

---

## Post 4 by @Twansparant — 2024-04-26T09:38:05Z

Yes, thanks!  
That was exactly what I was looking for!

---

## Post 5 by @Twansparant — 2024-04-26T11:26:16Z

How would you use this technique to also enqueue those assets in the **editor**?  
If I also add the example script to my `editor.js` entrypoint:

```
const editor = async () => {
  if (document.querySelector('.slider')) {
    const {slider} = await import('./slider.js')
    slider()
  }
}

editor()
```

The slider isn’t triggered since the **querySelector** won’t find anything here:  
`document.querySelector('.slider')`

I also tried wrapping it around the `domReady` call:

```
domReady(async () => {
  editor()
});
```

But same result, is there a callback available for when the editor has loaded all blocks?  
Thanks!

---

## Post 6 by @Twansparant — 2024-04-26T11:40:39Z

Ah I fixed that by using [this example](https://gist.github.com/KevinBatdorf/fca19e1f3b749b5c57db8158f4850eff):

```
import { select, subscribe } from '@wordpress/data'

export function whenEditorIsReady() {
    return new Promise((resolve) => {
        const unsubscribe = subscribe(() => {
            // This will trigger after the initial render blocking, before the window load event
            // This seems currently more reliable than using __unstableIsEditorReady
            if (select('core/editor').isCleanNewPost() || select('core/block-editor').getBlockCount() > 0) {
                unsubscribe()
                resolve()
            }
        })
    })
}

whenEditorIsReady().then(() => {
  if (document.querySelector('.slider')) {
    const {slider} = await import('./slider.js')
    slider()
  }
})
```

---

## Post 7 by @Twansparant — 2024-05-27T09:01:03Z

I’ve got a follow-up question regarding **[dynamic blocks](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/creating-dynamic-blocks/)**;  
I was following [this article](https://kinsta.com/blog/dynamic-blocks/) and [this example](https://gist.github.com/carlodaniele/27e292fbbe4b897ca3bda4539dfd74df) for creating a dynamic block.

I would like to use [Bud](https://bud.js.org/extensions/bud-preset-wordpress/editor-integration/blocks) to register my dynamic block and render it with the **Gutenberg React components** in the editor, but I want to render the front-end with **PHP** using a blade template.

I understand I have to register the same block both in **JS** as in **PHP** and just omit the `save()` function in JS, but how can I tell the PHP part to use a blade view and pass the block attributes, just like you would with an **ACF block**?

```
namespace App\Controllers;
use function Roots\view;

class Gutenberg
{
	public static function register_blocks()
	{
		register_block_type('ah/media-grid', [
			'render_callback' => view('blocks/media-grid', ['block' => $this])->render()
		]);
	}
}
add_action('init', ['App\Controllers\Gutenberg', 'register_blocks']);
```

My blade template:

```
<div>
@dump($block)
</div>
```

What parameter do I need to pass to blade. because I’m getting the error:

```
Using $this when not in object context
```

I was looking at how the [ACF Composer blocks](https://github.com/Log1x/acf-composer/blob/d380557ebe67c3b94aaed714bbe4eb25ec2b5944/src/Block.php) do that, but can’t seem to figure it out how to achieve the same in PHP?

Any tips? Thanks!

---

## Post 8 by @Twansparant — 2024-05-27T09:33:46Z

I’m answering my own question again, sorry about that :face_with_hand_over_mouth:  
But I found out that the poet **block** array is exactly meant for this use case:

In my `config/poet.php`:

```
return [
	'block' => [
		'ah/media-grid',
	],
]
```

Then I can completely remove that `register_block_type` action. In my blade view I now have these parameters available:

```
<div>
	@dump($data, $content)
	<div>{!! $content ?? '' !!}</div>
</div>
```

Awesome!  
The only thing that isn’t working yet are my `InnerBlocks`, in my `edit.js` I have:

```
import { InnerBlocks } from '@wordpress/block-editor'

const ALLOWED_BLOCKS = ['core/heading', 'core/paragraph', 'core/list', 'core/buttons', 'core/button']
const TEMPLATE = [
	['core/paragraph', {
		allowedFormats: ['core/bold', 'core/italic'],
		placeholder: __('Voeg tekst toe…')
	}]
]

export const edit = ({ attributes, setAttributes }) => {
	return (
		{/* ... other markup */}
		<InnerBlocks
			allowedBlocks={ALLOWED_BLOCKS}
			template={TEMPLATE}
		/>
	)
}

// export const save = () => null;
```

I can see the **InnerBlocks** in the editor and I can add text, but after saving it dissapears again? In my blade view `$content` is always `false`.

Any ideas what might go wrong?

**EDIT** : Sorry just had to add in `save` function:

```
/* Block save */
export const save = () => {
	return (
		<InnerBlocks.Content />
	)
}
```

---

## Post 9 by @jasperfrumau — 2024-08-14T06:39:32Z

I know this is old but I am also working on adding a block using Poet @Twansparant . See [Sage 10 + Poet block - Not loading](https://discourse.roots.io/t/sage-10-poet-block-not-loading/27893) . It seems I need to add `edit.js` and `edit.css` for my block , but I am not clear on how. I could add these to

- `resources/scripts/editor.js`
- `resources/styles/editor.css`

but I assume we do a separate JS at least as well as a save.js per block. How did you add these to your theme?
