# Register an ACF block with modern practices

**URL:** https://discourse.roots.io/t/register-an-acf-block-with-modern-practices/25887
**Category:** sage
**Created:** 2023-08-28T20:29:23Z
**Posts:** 8

## Post 1 by @djmtype — 2023-08-28T20:29:23Z

Is it possible to register an ACF block using `block.json`?

I’ve looked at this old post, but that still registers the block using `acf_register_block_type`

> [@How to register Gutenberg blocks using acf_register_block_type](https://discourse.roots.io/t/how-to-register-gutenberg-blocks-using-acf-register-block-type/23569):
>
> Have read up on using plugins to register blocks in Sage 10 but I was wondering if there is a way to register Guternberg blocks using the more traditional method of acf\_register\_block\_type. So far, I’ve created a new file: acf-blocks.php in the /app folder and have the acf/init action to register them. So an example would be: /resources/views/blocks/banner.php And have registered it successfully with: acf\_register\_block\_type(array( 'name' =\> 'banner', 'title' …

In my block.json:

```
"acf": {
		"mode": "preview",
		"renderTemplate": "/resources/views/blocks/dummy-box/dummy-box.php"

	}
```

ACF fails to see my template however.

BTW, I used this handy utility to create the block setup: [https://github.com/thetwopct/create-acf-block-json](https://github.com/thetwopct/create-acf-block-json)

---

## Post 2 by @djmtype — 2023-08-28T20:44:38Z

After registering it with the correct path, it seems to have found it, I think.

```
add_action( 'init', 'register_acf_blocks' );
function register_acf_blocks() {
    register_block_type( __DIR__. '/resources/views/blocks/dummy-box' );
}
```

Unfortunately, it doesn’t work with blade files; just strict php.

---

## Post 3 by @JamieBradders — 2023-09-24T14:07:25Z

Would love to understand if there is a way to make this work with the Blade files :crossed_fingers:

---

## Post 4 by @talss89 — 2023-09-24T20:10:25Z

It looks like [ACF provide a render callback](https://www.advancedcustomfields.com/resources/acf-blocks-key-concepts) for `block.json`:

> - `renderCallback` (string) (optional) Instead of providing a `render_template`, a callback function name may be specified to output the block’s HTML.
> 
> ```
> // Specifying a function
> "renderCallback": "my_acf_block_render_callback",
> ```

You could render a Blade view inside that callback using the `view()` function.

```
function your_blade_block_render_callback($block, $content, $is_preview, $post_id, $wp_block, $context) {
    echo view('blocks/example', compact('block', 'content', 'is_preview', 'post_id', 'wp_block', 'context'));
}
```

I haven’t tested this, but having a quick look at the ACF source shows that this is fired via `call_user_func` and return value discarded, so echoing rather than returning the output seems to be the way it’s supposed to work.

[Slightly adjacent to this is this page from the Acorn docs on rendering Blade views.](https://roots.io/acorn/docs/rendering-blade-views/)

---

## Post 5 by @ecruhling — 2023-10-11T21:03:20Z

here’s what I have been using:

```
/**
 * Register ACF Blocks.
 */
function theme_blocks_init()
{
    // Directory containing the blocks, within the 'resources/views' directory.
    $directory = resource_path('views') . '/blocks/';

    // Iterate over the directory provided and look for blocks.
    $block_directory = new DirectoryIterator($directory);

    foreach ($block_directory as $block) {
        if ($block->isDir() && !$block->isDot()) {
            register_block_type($block->getRealpath());
        }
    }
}

add_action('init', __NAMESPACE__. '\\theme_blocks_init');
```

all your blocks will go in /resources/views/blocks/, each in their own directory

so for example, a carousel block would go in /resources/views/blocks/carousel/

each block has a block.json, along with a corresponding blade file - the file has to be named the same as the block slug, so in this example it would be ‘carousel.blade.php’

in the block.json:

```
"acf": {
    "mode": "auto", // or whatever
    "renderCallback": "\\App\\blade_render_callback",
    "postTypes": ["page"], // or whatever
    "blockVersion": 2
  },
```

then your callback function:

```
/**
 * Callback for rendering Blade templates.
 * Name of the Blade template at resources/views/blocks/{title}.blade.php
 */
function blade_render_callback($block, string $content = '', bool $is_preview = false, int $post_id = 0)
{
    $slug = str_replace(THEME_BLOCK_SLUG . '/', '', $block['name']);
    $block['slug'] = $slug;

        echo \Roots\view('blocks.' . $block['slug'] . '.' . $block['slug'], ['block' => $block])->render();
}
```

this is a truncated example, but it should work barebones, if you define the THEME\_BLOCK\_SLUG constant. That is going to be the block namespace. So in this example in the block.json the name is ‘jf/carousel’ - therefore the THEME\_BLOCK\_SLUG would be ‘jf’. You can hardcode it if you want; I just have a bunch of theme constants set earlier in the file that I use.

---

## Post 6 by @djmtype — 2024-06-16T17:06:58Z

@ecruhling Sorry, it’s been awhile as it’s not every day I’m working on WP projects. Thanks very much for your response.

I followed your instructions, and can get everything working when using just a php template. Then, in `block.json` within the `acf `object I specify: “renderTemplate”: “testimonial.php”

However. using \*.blade.php instead, still hasn’t worked for me.

It’s probably something I’m not setting up correctly.

I have `app/blade_render_callback.php` with the callback function. Using `acf` as my namespace, and `theme_blocks_init()` added to my functions.php file.

**Update**

I’m able to use blade if the render function is referenced directly from within my functions.php file.

So, why doesn’t it work if I reference it from within app?

```
// app/blade_render_callback.php

<?php
namespace App;

/**
 * Callback for rendering Blade templates.
 * Name of the Blade template at resources/views/blocks/{title}.blade.php
 */
function blade_render_callback($block, string $content = '', bool $is_preview = false, int $post_id = 0)
{
  $slug = str_replace('acf' . '/', '', $block['name']);
  $block['slug'] = $slug;

  echo \Roots\view('blocks.' . $block['slug'] . '.' . $block['slug'], ['block' => $block])->render();
}
```

block.json

```
"acf": {
  "mode": "preview", 
   "renderCallback": "\\App\\blade_render_callback",
   "postTypes": ["page"], 
   "blockVersion": 2
},
```

---

## Post 7 by @ecruhling — 2024-06-17T16:18:31Z

if there aren’t any errors, I would make certain that your file structure has each block separate within the /resources/views/blocks/ directory, and with files like this (as an example):

```
/carousel/
    block.json
    carousel.blade.php
```

and the name key of the block within block.json, would be “name”: “acf/carousel”

(as you are using ‘acf’ as the block namespace)

---

## Post 8 by @lqze — 2025-02-10T00:14:18Z

@djmtype

Make sure you have loaded the blade\_render\_callback.php file within your Register Sage Theme Files Block within your functions.php.

```
/*
|--------------------------------------------------------------------------
| Register Sage Theme Files
|--------------------------------------------------------------------------
|
| Out of the box, Sage ships with categorically named theme files
| containing common functionality and setup to be bootstrapped with your
| theme. Simply add (or remove) files from the array below to change what
| is registered alongside Sage.
|
*/

collect(['setup', 'filters', 'blocks', 'blade_render_callback'])
   ->each(function ($file) {
       if (! locate_template($file = "app/{$file}.php", true, true)) {
           wp_die(
               /* translators: %s is replaced with the relative file path */
               sprintf(__('Error locating <code>%s</code> for inclusion.', 'sage'), $file)
           );
       }
   });
```

After doing that, change your the `renderCallback` line under the `acf` key in your `block.json` to:

```
"renderCallback": "blade_render_callback"
```
