Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Twig renderBlock #2944

Open
JacobPrice opened this issue Mar 6, 2024 · 2 comments
Open

Add Twig renderBlock #2944

JacobPrice opened this issue Mar 6, 2024 · 2 comments

Comments

@JacobPrice
Copy link

Is your feature request related to a problem? Please describe.

Currently, Timber's render method is designed to render entire templates. While this works well for most use cases, there are scenarios, especially in dynamic and hypermedia-driven applications (e.g., those using HTMX), where rendering only a specific part of a template (a block or fragment) would be more efficient and effective. This is particularly relevant when only a small portion of the page needs to be updated in response to an action, avoiding the overhead of rendering and sending the entire template over the network.

Describe the solution you’d like

I propose adding a new method, render_block. This method would allow developers to render specific blocks within a Twig template, without needing to render the entire template.

A high-level overview of this would look something like this:

    /**
     * Renders a specific block within a Twig template.
     * 
     * @param string $file Path to the Twig template.
     * @param string $block_name Name of the block to render.
     * @param array $data Data to be passed to the block for rendering.
     * @return string|false Rendered content of the block or false on failure.
     */
    public function render_block(string $file, string $block_name, array $data)
    {
        try {
            $twig = $this->get_twig();
            $template = $twig->load($file);

            if (!$template->hasBlock($block_name)) {
                // Handle the error as needed (log, throw exception, etc.)
                return false;
            }

            $output = $template->renderBlock($block_name, $data);

            return $output;
        }
        catch (\Exception $e) {
            // Handle exceptions as needed
            return false;
        }
    }

An additional argument $via_block_render could be added to Timber::compile() :

public static function compile($filenames, $data = [], $expires = false, $cache_mode = Loader::CACHE_USE_DEFAULT, $via_render = false, $via_block_render = null)

Lastly, a conditional would be added to the output within the compile method:

            if($via_block_render){
                $output = $loader->render_block($file, $via_block_render, $data);
            } else {
                $output = $loader->render($file, $data, $expires, $cache_mode);
            }

To make this accessible via the Timber class an additional method could be added called render_block:

    /**
     * Renders a Twig block from a Twig file.
     *
     * Passes data to a Twig file and echoes the output of a specific block.
     *
     * @api
     * @example
     * ```php
     * $context = Timber::context();
     *
     * Timber::render_block( 'index.twig', 'content', $context );
     * ```
     * @param array|string   $filenames      Name or full path of the Twig file to render. If this is an array of file
     *                                       names or paths, Timber will render the first file that exists.
     * @param string         $block_name     The name of the block to render.
     * @param array          $data           Optional. An array of data to use in Twig template.
     * @param bool|int|array $expires        Optional. In seconds. Use false to disable cache altogether. When passed an
     *                                       array, the first value is used for non-logged in visitors, the second for users.
     *                                       Default false.
     * @param string         $cache_mode     Optional. Any of the cache mode constants defined in Timber\Loader.
     */
    public static function render_block(string $template, $block_name, array $data = [], $expires = false, $cache_mode = Loader::CACHE_USE_DEFAULT)
    {
        $output = self::compile($template, $data, $expires, $cache_mode, true, $block_name);
        echo $output;
    }

Describe alternatives you’ve considered

An alternative is to use twig partials and include them. This allows for those specific areas to be rendered as needed, but also leads to a slightly more fragmented development experience making it harder to understand the template as a cohesive unit.

Additional context

The above is a working prototype, but I'm sure it could be improved. I'd be more than happy to take some feedback and submit a PR if this is something Timber would benefit from.

Potentially missing things:
Implement Timbers standard practice for handling errors/exceptions
Maybe some filters are needed?
Maybe this should be in a separate compilation?

https://twig.symfony.com/doc/3.x/api.html#rendering-templates
https://htmx.org/essays/template-fragments/

@JacobPrice
Copy link
Author

@Levdbas Is this worth making a PR for? It could be a straightforward implementation that could allow for more code organization.

@Levdbas
Copy link
Member

Levdbas commented May 3, 2024

Hey @JacobPrice ,

I think this would be a welcome addition but it does needs it's own documentation and tests. Are you willing to provide those as well? We can help out with the tests if that holds you back. Documentation wise I would like to add a guide on how to use this feature in the wild with a platform/framework of choice so it can benefit the whole Timber community. Let me know if you have any questions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants