Twig icon indicating copy to clipboard operation
Twig copied to clipboard

[FR] give include an optional endinclude

Open hiasl opened this issue 3 years ago • 2 comments

In our project (Craft CMS) we have some common html patterns, which would ideally be wrapped around user content based on a "style" selection. E.g. an image gallery which either appears as slides or as thumbnails based on the surrounding html.

For this purpose we would like to create partials, which contain the different patterns / surrounding html. Ideally we would include the patterns AROUND the user generated content.

There are multiple ways to handle this with TWIG, like

  • using include and pass the content as a variable
  • using embed and passing the content as a block
  • using apply and a special wrapincfilter (wrap-include) we created as extension, which workarounds that requirement:

The main file:

{% apply wrapincfilter('wrapinc-include', {class: 'turbo'}) %}
    This is wrapped. Today's date: {{ 'now'|date('d.m.Y') }}
{% endapply %}

wrapinc-include:

<div class="{{ class }}">
    {{ _wrapped }}
</div>
  • But by far the nicest way for us would be this:
{% include 'wrapinc-include' with {class: 'turbo'} %}
This is wrapped. Today's date: {{ 'now'|date('d.m.Y') }}
{% endinclude %}

The wrapped content should be provided as some reserved-name variable (or any other best practice) to the included file.

Conclusion: The Feature Request is: give {% include %} an optional {% endinclude %}

hiasl avatar Jul 27 '22 06:07 hiasl

A tag that sometimes has a body and a closing tag and sometimes does not have it, without any difference in the opening tag creates an ambiguous syntax. So this is a no-go.

stof avatar Jul 27 '22 19:07 stof

Well the set tag works that way, so the difference must the = following the variable name, right?

Options would be to give it an extra attribute, like 'with-body', an attribute to specify the var name for the body or create a new tag for it.

  • Variant 1a:
{% include 'wrapinc-include' with-body with {class: 'turbo'} %}
This is wrapped. Today's date: {{ 'now'|date('d.m.Y') }}
{% endinclude %}
  • Variant 1b:
{% include 'wrapinc-include' body='_wrapped' with {class: 'turbo'} %}
This is wrapped. Today's date: {{ 'now'|date('d.m.Y') }}
{% endinclude %}
  • Variant 2:
{% wrapinclude 'wrapinc-include' with {class: 'turbo'} %}
This is wrapped. Today's date: {{ 'now'|date('d.m.Y') }}
{% endwrapinclude %}

I'd prefer 1b.

Any further ideas or feedback appreciated.

hiasl avatar Jul 27 '22 20:07 hiasl

In case of the {% set %}, the presence of the = followed by an expression in the opening tag is indeed the thing doing the switch between the 2 syntaxes.

stof avatar Oct 24 '22 13:10 stof

OK. I understand. Do you see any necessity for my use case at all?

Because my suggestions from the last post would all have distinctions to allow this non-ambiguous syntax.

My initial suggestions to work with apply and a "wrapincfilter" does not work, because TWIG first expects an endapply before interpreting any other TWIG code. And include with a variable or embed are not as nice.

hiasl avatar Oct 24 '22 13:10 hiasl

I think embed is the best for your use-case. It allows to override some blocks of the included template.

{# main.twig #}
{% embed "included.twig" with { class: 'turbo' } %}
  {% block body %}
    This is wrapped. Today's date: {{ 'now'|date('d.m.Y') }}
  {% endblock %}
{% endembed %}
{# included.twig #}
<div class="{{ class }}">
    {{ block('body') }}
</div>

The only difference with your "by far the nicest way" is that you need the {% block body %} tag to name the block, instead of a variable _wrapped named by convention.

GromNaN avatar Jan 13 '23 12:01 GromNaN

yes, thats a good solution, thank you!

hiasl avatar Jan 25 '23 20:01 hiasl