8

Is there any way to use a macro in twig to define a variable outside that macro?

For example, say you want to use a macro to set a variable that stores an entry's parent (I know you can do this much simply, but I have my reasons to want to do it like this), I would intuitively want to do something like this:

{% macro getParentEntry(thisEntry) %}

    {% import _self as self %}

    {% if thisEntry.parent|length %}

        {% set parent = thisEntry %}

    {% else %}

        {% set parent = false %}

    {% endif %}

{% endmacro %}

{% import _self as self %}
{% set parent = self.getParentEntry( entry ) %}

But this clearly isn't quite right.

Am I missing something, or is this just not possible. (I couldn't find any mention of anything like this in the twig documentation.)

Many thanks!

2 Answers 2

12

I think the issue with trying to set a variable in a macro is that the variable is limited to the scope of the macro you are triggering, so {% set parent = thisEntry %} is available within the scope of your macro, but doesn't define it for the rest of your template.

Macros are comparable with functions in regular programming languages. They are useful to put often used HTML idioms into reusable elements to not repeat yourself.

Macros differs from native PHP functions in a few ways:

  • Default argument values are defined by using the default filter in the macro body;
  • Arguments of a macro are always optional.
  • But as with PHP functions, macros don't have access to the current template variables.

Taken from the Twig docs

So due to the limitations in scope and the nature of macros, they are meant to be used to just output reusable code, not set and define logic in your templates. So everything is just rendered as a string (models have their __toString() method called)

The way you could get this to work for you is to just output whether or not the logic in your macro is true or null, then do the rest of the logic in your template, something like:

{% macro hasParentEntry(thisEntry) %}

 {% import _self as self %}

 {% if thisEntry.parent|length %}

   {# would output 1 #}
   {{ true }}

 {% else %}

   {# or just output null #}
   {{ null }}

 {% endif %}

{% endmacro %}

Then in your template do something like:

{# This will either be true or null #}
{% set parent = self.hasParentEntry( entry ) %}

{% if parent %}

 {# this will set your parent variable to the entry model or leave the variable as null #}
 {% set parent = entry.parent %}

{% endif %}
2
  • Great explanation. And a very useful suggestion given the limitations. Thanks alot Alec! Jun 9, 2015 at 16:26
  • Not a problem @negatron :) Jun 9, 2015 at 19:01
9

A little bit late but maybe someone else has the same issue and want's to accomplish this. You can use this Plugin Twig Perversion to create macros that return values

{% macro getParentEntry(thisEntry) %}
    {% import _self as self %}
    {% if thisEntry.parent|length %}
        {% set parent = thisEntry.parent %}
    {% else %}
        {% set parent = false %}
    {% endif %}
    {% return parent %}
{% endmacro %}

And you can use it with

{% set parent = self.getParentEntry( entry ) %}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.