Register an ACF block with modern practices

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

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

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.

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

It looks like ACF provide a render callback 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.

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.

@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
},

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)