<p>So I took another approach to my problem and ended up creating a plugin variable allowing me to set data inside a macro and have it accessible in the template. It's not complicated and does the trick.</p>

<pre><code>class MyPluginVariable
{
  /**
   * Store data for use within both
   * templates and macros. Easy way around
   * macros having their own context
   * @var [Array]
   */
  private static $store = [];

  /**
   * Set data in storage array
   * @param [String] $key
   * @param $value
   */
  public function set($key, $value) {
    self::$store[$key] = $value;
  }

  /**
   * Retrieve data from storage array
   * @param  [String] $key
   */
  public function get($key) {
    return self::$store[$key];
  }
}
</code></pre>

<p>To set data you simply call <code>{% do craft.MyPlugin.set('myVar', true) %}</code> and to retrieve it <code>{% set myVar = craft.MyPlugin.get('myVar') %}</code></p>

CC BY-SA 3.0
2015-10-01T23:51:02.043Z
2015-10-23T03:27:19.173Z
2015-10-23T03:27:19.173Z
Fyrebase
<p>You were close with the extension… here's a function that sets the context by reference:</p>
<pre class="lang-php prettyprint-override"><code>namespace mytikilife\twig;

use Twig\Extension\AbstractExtension;

class MyExtension extends AbstractExtension
{
    public function getFunctions(): array
    {
        return [
            new \Twig\TwigFunction('set_context_defaults', [$this, 'setContextDefaults'], ['needs_context' =&gt; true]),
        ];
    }

    /**
     * @param $context
     * @param $defaults
     */
    public function setContextDefaults(array &amp;$context, array $defaults) {
        foreach($defaults as $key =&gt; $value) {
            if(!isset($context[$key])) {
                $context[$key] = $value;
            }
        }
    }
}
</code></pre>
<p>The trick is to add <code>['needs_context' =&gt; true]</code> to the <code>getFunction</code> return value.</p>
<p>You can then use it in templates like this:</p>
<pre><code>{% do set_context_defaults({
    entry: entry,
    heading_html: 'Trading Post',
    heading_tag: 'h2',
    with_heading: true,
    lazy: craft.app.request.getParam('lazy', false),
    lazy_url: url(entry.url ~ '/trading-post', { lazy: false }),
    id: 'tiki-mugs-'~ entry.id ~'-trading-post'
}) %}
</code></pre>

CC BY-SA 4.0
2021-03-15T02:35:54.763Z
2021-03-15T02:35:54.763Z
Leevi Graham
<p>From a quick glance, I don't think this is possible. In that function, the context is being passed in by value, not reference... So any changes are only to the local scope.</p>

CC BY-SA 3.0
2015-09-12T03:11:32.290Z
Thanks @jeremy. I've also tried passing it in by reference with the same result.
Fyrebase
CC BY-SA 3.0
2015-09-11T13:18:31.383Z
2015-09-11T13:18:31.383Z
Jeremy Daalder
<p>I'm trying to update the context from within a macro. Is this possible at all? I'm pretty close with the below code.</p>

<p>The var_dump within the below function shows the updated context. But when doing a <code>{{ dump(_context|keys) }}</code> after the macro call the context is unchanged.</p>

<p>Any ideas, much appreciated.</p>

<pre><code>&lt;?php
namespace Craft;

class TwiggedTwigExtension extends \Twig_Extension
{
  public function getName()
  {
    return 'Twigged';
  }

  public function getFunctions()
  {
    return array(
      'addVar' =&gt; new \Twig_SimpleFunction('addVar', array($this, 'addVar'), array('needs_context' =&gt; true)),
    );
  }

  public function addVar($context, $str, $val)
  {
    $context['context'][$str] = $val;
    var_dump(array_keys($context['context']));
  }
}
</code></pre>

CC BY-SA 3.0
2015-09-11T13:20:03.903Z
Are you referring to a macro as defined with `{% macro %}` or this custom Twig Extension? If you're referring to an extension, I recommend going to StackOverflow as they will have more twig-related answers than we will.
Bryan Redeagle
CC BY-SA 3.0
2015-09-11T13:35:01.630Z
Even calling the function in the template without the macro like so `{{ addVar('hello', 'world') }}` results in the same. I have also tried passing context by reference.
Fyrebase
<templating><macro>
Add / Update context from macro
# Add / Update context from macro

(Asked by: username_0 on 2015-09-11)

I'm trying to update the context from within a macro. Is this possible at all? I'm pretty close with the below code.
The var_dump within the below function shows the updated context. But when doing a {{ dump(_context|keys) }} after the macro call the context is unchanged.
Any ideas, much appreciated.
 new \Twig_SimpleFunction('addVar', array($this, 'addVar'), array('needs_context' => true)),
    );
  }

  public function addVar($context, $str, $val)
  {
    $context['context'][$str] = $val;
    var_dump(array_keys($context['context']));
  }
}

**Tags:** templating, macro
> **Comments:**
> **username_1**: Are you referring to a macro as defined with `{% macro %}` or this custom Twig Extension? If you're referring to an extension, I recommend going to StackOverflow as they will have more twig-related answers than we will.  
> **username_0**: Even calling the function in the template without the macro like so `{{ addVar('hello', 'world') }}` results in the same. I have also tried passing context by reference.  

---

## 3 answers

### Answer by username_0 on 2015-10-01. Score: 2 | Accepted answer

So I took another approach to my problem and ended up creating a plugin variable allowing me to set data inside a macro and have it accessible in the template. It's not complicated and does the trick.
class MyPluginVariable
{
  /**
   * Store data for use within both
   * templates and macros. Easy way around
   * macros having their own context
   * @var [Array]
   */
  private static $store = [];

  /**
   * Set data in storage array
   * @param [String] $key
   * @param $value
   */
  public function set($key, $value) {
    self::$store[$key] = $value;
  }

  /**
   * Retrieve data from storage array
   * @param  [String] $key
   */
  public function get($key) {
    return self::$store[$key];
  }
}

To set data you simply call {% do craft.MyPlugin.set('myVar', true) %} and to retrieve it {% set myVar = craft.MyPlugin.get('myVar') %}


---

### Answer by username_2 on 2021-03-15. Score: 1

You were close with the extension… here's a function that sets the context by reference:
namespace mytikilife\twig;

use Twig\Extension\AbstractExtension;

class MyExtension extends AbstractExtension
{
    public function getFunctions(): array
    {
        return [
            new \Twig\TwigFunction('set_context_defaults', [$this, 'setContextDefaults'], ['needs_context' => true]),
        ];
    }

    /**
     * @param $context
     * @param $defaults
     */
    public function setContextDefaults(array &$context, array $defaults) {
        foreach($defaults as $key => $value) {
            if(!isset($context[$key])) {
                $context[$key] = $value;
            }
        }
    }
}

The trick is to add ['needs_context' => true] to the getFunction return value.
You can then use it in templates like this:
{% do set_context_defaults({
    entry: entry,
    heading_html: 'Trading Post',
    heading_tag: 'h2',
    with_heading: true,
    lazy: craft.app.request.getParam('lazy', false),
    lazy_url: url(entry.url ~ '/trading-post', { lazy: false }),
    id: 'tiki-mugs-'~ entry.id ~'-trading-post'
}) %}


---

### Answer by username_3 on 2015-09-11. Score: 1

From a quick glance, I don't think this is possible. In that function, the context is being passed in by value, not reference... So any changes are only to the local scope.

> **Comments:**
> **username_0**: Thanks @jeremy. I've also tried passing it in by reference with the same result.  

---

