Skip to content

Conversation

@JacobPrice
Copy link

Related:

Issue

Twig has a built-in way to render blocks from a twig file instead of the entire file. Timber does not have this implemented.
Twig for Developers - Documentation - Twig PHP

Solution

Add two new methods that leverage pre-existing methods.

  • Timber::render_block
  • Timber::compile_block

By adding an additional parameter called $block_name to the render method of the Loader class and to the compile function of the Timber class we can use the current compile function.

If a $block_name is passed and exists within the template provided, then twigs renderBlock is used.

Impact

The primary goal of this change is to address a feature request as mentioned in #2944.

This article highlights some of the general ideas that inspired this feature addition: </> htmx ~ Template Fragments

Usage Changes

Considerations

Potentially a seperate compile method could be used, but I am unsure of where this would be applicable past the current filters that are already in place for the current compile method.

It may be worth throwing an error instead of continuing if the block is not found found in a template or returning false.

As discussed in #2944 it would be a good idea to add some documentation.

The two primary uses that I have found and would be benefiting from are in hypermedia systems (htmx) uses and for reducing files.

Examples -

HTMX/AJAX/FETCH:
Rendering post block in pagination instead of splitting this into a seperate file.

File Reduction:
Instead of something like toast-success.twig, toast-fail.twig, toast-info.twig all of these could live in a toast.twig file and render each block from there.

Testing

Not included, but would be caught by other unit tests.

@coveralls
Copy link

coveralls commented Oct 16, 2024

Coverage Status

coverage: 88.233% (+0.3%) from 87.972%
when pulling e5ffcac on JacobPrice:2.x-render_block
into 55acea4 on timber:2.x.

@Levdbas
Copy link
Member

Levdbas commented Nov 8, 2024

Hi @JacobPrice ,

Love the addition. We discussed this during our 2.3.0 release meeting and we would like to add some guides on how to use this in the wild as well. This is a pretty big feature that could use some guidence on how/when to use this.

Maybe you and @jasalt can work on a guide on how to use this functionality together? Jarkko came up with some examples of using a similar use case via #3044 and maybe that can be used in conjunction with your code?

@jasalt
Copy link
Contributor

jasalt commented Nov 8, 2024

Thank's for considering @Levdbas. Looking at the render_block implementation, I could give it a go if @JacobPrice can provide some rough examples or instructions, relating to some common use case, how would you see that?

I could use it in some of my projects and supply tutorial/doc improvements, edit suggestions, or code examples that I might see generally useful. Practically I'm mostly interested in having some general HTMX user interface patterns working like endless scroll, active search, pop up carts for web store themes and such with Timber themes, and maybe also plugins.

I added an update just now on some further experiments I had with the same technique I mentioned at #3044, related to multi-language production site project from which I extracted that initial example from while it was in progress. Quite happy already how it works with that plugin already but sure I would be happy to improve.

@JacobPrice
Copy link
Author

@Levdbas I will work on putting something together for this. It's a feature that would largely be a preference, as it allows for less code separation, which in some cases may be beneficial.

Another thing that may be worth adding would be a render_block twig function. That would allow for this function to be used inside of a twig file, which sounds odd, but in practice seems to feel nice.

This is a simplistic example:

<!DOCTYPE html>
<html lang="en">
<body>
    {{ render_block(toast_type, 'toasts.twig', {message: toast_message}) }}
    <main>
    {# ... Content ... #}
    </main>
</body>
</html>
{# toasts.twig #}
{% set common_classes = 'top-0 left-0 w-full p-4' %}

{% block error %}
<div class="bg-red-500 text-red-50 font-bold {{ common_classes }}" role="alert">{{ message }}</div>
{% endblock %}

{% block warning %}
<div class="bg-yellow-500 text-yellow-50 {{ common_classes }}" role="alert">{{ message }}</div>
{% endblock %}

{% block success %}
<div class="bg-green-500 text-green-50 {{ common_classes }}" role="alert">{{ message }}</div>
{% endblock %}

{% block info %}
<div class="bg-blue-500 text-blue-50 {{ common_classes }}" role="alert">{{ message }}</div>
{% endblock %}

@Levdbas
Copy link
Member

Levdbas commented Dec 18, 2024

Ah Gotcha @JacobPrice , this looks great. But with the changes made a render_block function in twig files is not available yet, right?

Things that, in my opinion, are still needed in this PR:

  • Unit tests to test this new functionality, if you need help with that, let me know!
  • further documentation inside the function doc block on how to use this. You can use this example to further enhance the documentation by including examples in multiple languages
  • check if the function also works as intended inside twig files as you show in your example

@gchtr
Copy link
Member

gchtr commented Dec 23, 2024

Thanks for all your work on this so far. This is a great feature!

In addition to the points that @Levdbas listed, I would like to propose we switch the naming from "block" to "twig_block".

I feel like having methods named render_block or compile_block could lead to confusion with the methods that WordPress provides for the block editor. There’s a WordPress function called render_block().

If people see code like the following in Twig, they might think it’s an implementation that renders a WordPress block, if they don’t know about Twig blocks yet.

{{ render_block(toast_type, 'toasts.twig', {message: toast_message}) }}

Yes, there’s no functionality to handle WordPress blocks through Twig templates in Timber, but there might be in the future.

I would like it much better if we could add the disambiguation and use render_twig_block instead:

{{ render_twig_block(toast_type, 'toasts.twig', {message: toast_message}) }}

I would use:

  • render_twig_block instead of render_block
  • compile_twig_block instead of compile_block
  • Each time we write about Twig blocks, we should call them "Twig blocks" instead of just "blocks".

@Levdbas
Copy link
Member

Levdbas commented Jan 3, 2025

Hi @JacobPrice , best wishes! We would like to include this function if you can take on some or all of the things mentioned in the two comments before this one. If you need any help with this, let me know!

@Levdbas
Copy link
Member

Levdbas commented Aug 28, 2025

Hey @JacobPrice , @gchtr @jasalt ,

I found some time to iterate on this. I renamed the functions, added docblocks and added tests. I've also added the render_twig_block twig function. @gchtr , I had to write some custom loader logic here for reasons I don't completely understand. Can you take a look at this?

And everyone else, please take a good look at the changes as well. Preferably I would still like to add a guide on how to use this in the "wild". Is somebody to do that while also testing my code?

@Levdbas Levdbas changed the title Add render_block method Add render_twig_block method Aug 28, 2025
@jasalt
Copy link
Contributor

jasalt commented Aug 29, 2025

@Levdbas sure, I’ll experiment soon-ish and write something about it. Glad to see this moving forward.

@Levdbas Levdbas requested a review from Copilot September 4, 2025 10:30
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for rendering specific Twig blocks from template files, implementing the render_twig_block and compile_twig_block methods to address feature request #2944. This functionality enables developers to render individual blocks from Twig templates instead of entire files, which is particularly useful for HTMX applications and reducing template file duplication.

Key changes:

  • Added render_twig_block and compile_twig_block methods to the Timber class
  • Extended the Loader's render method to support block-specific rendering using Twig's renderBlock functionality
  • Added a render_twig_block Twig function for use within templates

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/Timber.php Added new public methods for block rendering with comprehensive documentation
src/Loader.php Extended render method to support optional block name parameter with fallback behavior
src/Twig.php Added render_twig_block Twig function for template usage
tests/test-timber-render-block.php Comprehensive test suite covering various block rendering scenarios
tests/assets/*.twig Test template files with different block structures for testing

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Levdbas and others added 5 commits September 4, 2025 12:48
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@Levdbas
Copy link
Member

Levdbas commented Sep 4, 2025

Added some documentation as well now in f0f7236. I haven't had the time to test the docs though. Will do that later or if somebody else is willing to do so, that would be nice!

Copy link
Member

@gchtr gchtr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My gut feeling says that adding a $block_name parameter to the Timber::compile() and Timber::render() function is not the right solution for this. I feel that this would somehow bite us in the future when we need to incorporate other functionality.

Ideally, we would extract the logic from render() and compile() into a separate method that can be reused by render_twig_block() and compile_twig_block().

And maybe we need to use a different loader that extends Timber\Loader instead of adding the logic and more parameters to the existing loader. Maybe we’ll have a TwigLoader and a TwigBlockLoader using a decorator pattern?

I’m not sure yet about the best way to do this.

@jasalt
Copy link
Contributor

jasalt commented Sep 15, 2025

Thinking about the final form of this might be wise.

Just noted that upcoming Django 6 includes this sort of functionality from django-template-partials to Django core, this could give some reference also.

@jasalt
Copy link
Contributor

jasalt commented Sep 18, 2025

Evaluating tools for a new Django project and with the Django 6 it looks like the trick there is that partial name is appended to template name that is passed to the same render function:

The template partial in authors.html:

{% partialdef user-info %}
    {# ... #}
{% endpartialdef user-info %}

... other template content continues ...

Rendering it with context:

render(request, "authors.html#user-info", {"user": user})

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants