Using twig variable to dynamically call an imported macro sub-function

Dynamic macros may not be supported in Twig.

But there is a simple workaround since you can dynamically include other templates.

Example:
Let's say you have a bunch of content modules or content blocks (or however you wanna call them) for your site. And you have Twig macros responsible of rendering each of these modules.

{# modules.twig #}

{% macro module1(config) %}
  <div>module one</div>
{% endmacro %}

{% macro module2(config) %}
  <div>module two</div>
{% endmacro %}

{% macro module3(config) %}
  <div>module three</div>
{% endmacro %}

Now, what you need to dynamically call these macros is to add an extra template for each, like so:

{# module1.twig #}

{% import "modules.twig" as modules %}
{{ modules.module1(config) }}
{# module2.twig #}

{% import "modules.twig" as modules %}
{{ modules.module2(config) }}
{# module3.twig #}

{% import "modules.twig" as modules %}
{{ modules.module3(config) }}

Finally, in your actual page template you just include the template instead of calling the macro.

{# template.twig #}

{# this is the macro's name to be called #}
{% set macro = 'module2' %}
{# this is just a config object to be passed to the macro #}
{% set config = {} %}

{% include macro ~ '.twig' with { config: config } only %}

Et voilá, (dynamically produced) output will be <div>module two</div>.


I just thought other people may want the answer to this, as provide by fabpot:

This is indeed something that is not supported: calling a macro with a dynamic name (I have added a proper exception to be clearer about the issue).

If you really want to do that, you can do so with the following code:

{{ attribute(forms, element.type, [element.name,element.value,element.atts]) }}

-fabpot

https://github.com/twigphp/Twig/issues/922#issuecomment-11133299

Tags:

Twig