Support

Account

Home Forums Gutenberg Setting the gutenberg block render callback dynamically

Solved

Setting the gutenberg block render callback dynamically

  • 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.

Viewing 3 posts - 1 through 3 (of 3 total)

The topic ‘Setting the gutenberg block render callback dynamically’ is closed to new replies.