How can I access template variable in TWIG macro?
Asked Answered
F

5

23

I'm not able to access template variable in TWIG macro.

Here is a simplified example:

{% set myname = "Ligio" %}
{{ _self.pagedurl(1) }}

{% macro pagedurl(page) %}
    Hi {{ _self.myname }}! This is Page Num {{ page }}
{% endmacro %}

How can I access the variable myname without passing it to the macro?

Forethought answered 27/2, 2013 at 8:52 Comment(2)
Did you try a simple {{ myname }}?Effluvium
with {{ myname }} I'm not in the scope of the variable... It's not working!Forethought
A
25

You can not.

As stated in the documentation:

As PHP functions, macros don't have access to the current template variables.

Your only solution is to pass the parameter to the macro:

{% import _self as flow %}
{{ flow.pagedurl(1, "Ligio") }}

{% macro pagedurl(page, myname) %}
    Hi {{ myname }}! This is Page Num {{ page }}
{% endmacro %}

IMPORTANT NOTE:

You may have noticed in my example, I call {% import _self as flow %}.
This is something you MUST do:

When you define a macro in the template where you are going to use it, you might be tempted to call the macro directly via _self.input() instead of importing it; even if seems to work, this is just a side-effect of the current implementation and it won't work anymore in Twig 2.x.

http://twig.sensiolabs.org/doc/tags/macro.html

Amenity answered 2/3, 2013 at 17:23 Comment(4)
One solution that can "hack" your "globals" is to build a twig var (or use _context) as an array of your important variables and then pass this single twig var as the last argument to any macro you use. --------- When within the scope of your macro you can then access this final argument via the varargs property. for example: {% set MyGlobals = varargs[0] %}Roots
It seems with Twig 3.x we don't need to import _self and you should not.Vivisection
The documentation justification seems ridiculous. PHP functions may have access to global variables, and PHP methods have access to class members. They could just stay it's by design instead of trying to blame it on PHP.Ivanovo
Quoting Symfony docs, it's about the Twig version (twig.symfony.com/doc/2.x/tags/macro.html): "Auto-import is only available as of Twig 2.11. For older versions, import macros using the special _self variable for the template name:"Sikata
G
14

If you need to pass more than one global variable into the macro, you might find the _context variable useful:

{% macro mymacro(globalvars) %}
    Value of the global variable pi is {{ globalvars.pi }}
{% endmacro %}

{% set pi = 3.14159 %}
{{ _self.mymacro(_context) }}

Ref: this or this answer.

Giantism answered 24/12, 2014 at 13:25 Comment(0)
C
2

You can set a global variable and access it anywhere in the template

$loader = new \Twig_Loader_Filesystem('path/to/templates');
$twig = new \Twig_Environment($loader);
$twig->addGlobal('V_Name', 'V_Value');
Cayenne answered 14/5, 2020 at 0:10 Comment(1)
Thanks, this is indeed the best solution when working with Timber/Twig/WordPress.Vienna
H
0

For those who want to use a template var in macros without passing it around every time (symfony)

Created a Twig AppExtension Service with private $var and getter/setter

  class AppExtension extends AbstractExtension
  {
        private $var;
    
        public function getFunctions(): array
        {
            return [
                new TwigFunction('setVar', [$this, 'setVar']),
                new TwigFunction('getVar', [$this, 'getVar'])
            ];
        }
    
        public function setVar(Article $article)
        {
            $this->var = $article;
        }

        public function getVar()
        {
            return $this->var;
        }
  }

Set your var inside your template.html.twig

{% from '.../macros.html.twig' import showTitle, showImage %}
{{ setVar(article) }}

{{ showTitle('foo') }}
{{ showImage('bar') }}

You can now use getVar() to access article in macros.html.twig

{% macro showTitle(className) %}
    <p class="{{ className }}">{{ getVar().title }}</p>
{% endmacro %}

{% macro showImage(className) %}
    <img class="{{ className }}" src="{{ getVar().image }}"/>
{% endmacro %}

NB: may not be the most efficient solution, but works great

Hammerskjold answered 23/2, 2024 at 11:54 Comment(1)
You could remove the setVat part by just settings the needs_context option to true thoughSkier
D
0

This doesn't help if the original value has to be a variable, but otherwise you can assign the value to a macro - the equivalent of a "getter": Your code would be:

{% macro myname() %}Ligio{% endmacro %}
{{ _self.pagedurl(1) }}

{% macro pagedurl(page) %}
    Hi {{ _self.myname() }}! This is Page Num {{ page }}
{% endmacro %}
Discretional answered 12/4, 2024 at 13:58 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.