I am trying to tackle registering gutenberg blocks in a more object oriented way. My goal is to eventually only have to write something like this:
$my_block = new GutenbergBlock($args);
$my_block->register_with_acf();
The problem I am running into is when I have to set the render_callback function. The function acf_register_block() wants a string of the function name to use as part of the arguments and I would like that function to be a method on the class or maybe set by a method on the class, maybe a method that returns the an anonymous function based on certain class properties. I want to dynamically give it something callable through a class function.
I currently don’t see any way of doing that since the render callback function requires the $block variable as well as a couple others and those pieces of context are not present in my class context. I feel like if there was some way to hook into the render_callback process and add to the context I could also pass in other properties from my class to use in the render_callback.
A practical example is when I want to use Timber and twig to render the block. I need to write something like this in my callback function:
function my_render_callback($block, $content = '', $is_preview = false)
{
$context = Timber::get_context();
Timber::render($name_of_template_file, $context);
}
Right now, I cannot get that $name_of_template_file to be dynamic because the render function is called in a completely different context than my class and I’d normally set that in my class. I’ve resorted to use a templating file structure that mirrors the name of the block to at least make it partially dynamic. This way I can write something like:
$new_block = new GutenbergBlock(array('name' => 'my-cool-block'));
Then in my callback function for that class I write:
Timber::render('template-parts/' . $block[name] . '.twig');
This at least makes it partially dynamic, but not all the way. I would love to not have to stick to a folder structure and just pass in that template variable dynamically somehow. But since the render callback is called in a different context than my class I cannot. At least not yet. I could be missing something completely obvious to a more skilled PHP programmer.
That was a super long-winded post. I hope someone else knows a solution or at least sympathizes with my plight. Or at the very least even understands what I am saying.
You can not only pass a string as the render_callback
. You could also pass an anonymous function, plus PHP treats an [$object, 'methodName']
array as a callable.
Here’s the Block
class i came up with. Check register()
to see how it specifies an instance method as the render_callback.
namespace Foo;
use Timber\Timber;
abstract class Block
{
abstract public function getName(): string;
abstract protected function getTitle(): string;
abstract protected function getDescription(): string;
abstract protected function getCategory(): string;
abstract protected function getIcon(): string;
abstract protected function getKeywords(): array;
abstract protected function getTemplateFilename(): string;
abstract protected function defineFields(): array;
protected function filterSupports(array $supports): array
{
return $supports;
}
protected function filterContext(array $context): array
{
return $context;
}
public function register()
{
acf_register_block_type([
'name' => $this->getName(),
'title' => $this->getTitle(),
'description' => $this->getDescription(),
'category' => $this->getCategory(),
'icon' => $this->getIcon(),
'keywords' => $this->getKeywords(),
'render_callback' => [$this, 'render'],
'mode' => 'edit',
'supports' => $this->filterSupports([
'align' => false,
'align_text' => false,
'alignt_content' => false,
'mode' => true,
'multiple' => true,
]),
]);
$this->registerFields();
}
private function registerFields()
{
acf_add_local_field_group([
'key' => 'group_block_' . $this->getName(),
'title' => $this->getTitle(),
'fields' => $this->defineFields(),
'active' => true,
'location' => [
[
[
'param' => 'block',
'operator' => '==',
'value' => 'acf/' . $this->getName(),
],
],
],
]);
}
public function compile(array $block): string
{
$context = $this->filterContext($block['data']);
return Timber::compile($this->getTemplateFilename(), $context);
}
public function render(array $block)
{
echo $this->compile($block);
}
public function dynamicRender(string $content, array $block): string
{
return $content;
}
}
I will try this out! Thanks for replying to a super old post I made lol! I figured out how to dynamically pass a render template string but not a render callable. This is great.
The topic ‘Setting the gutenberg block render callback dynamically’ is closed to new replies.
Welcome to the Advanced Custom Fields community forum.
Browse through ideas, snippets of code, questions and answers between fellow ACF users
Helping others is a great way to earn karma, gain badges and help ACF development!
We use cookies to offer you a better browsing experience, analyze site traffic and personalize content. Read about how we use cookies and how you can control them in our Privacy Policy. If you continue to use this site, you consent to our use of cookies.