Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-10-01T23:51:02.043Z
Answers.LastActivityDate: 2015-10-23T03:27:19.173Z
Answers.LastEditDate: 2015-10-23T03:27:19.173Z
Answers.UserDisplayName: Fyrebase
Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-15T02:35:54.763Z
Answers.LastActivityDate: 2021-03-15T02:35:54.763Z
Answers.UserDisplayName: Leevi Graham
Answers.Body: <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>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-09-12T03:11:32.290Z
Answers.Text: Thanks @jeremy. I've also tried passing it in by reference with the same result.
Answers.UserDisplayName: Fyrebase
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2015-09-11T13:18:31.383Z
Answers.LastActivityDate: 2015-09-11T13:18:31.383Z
Answers.UserDisplayName: Jeremy Daalder
Body: <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>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2015-09-11T13:20:03.903Z
Comments.Text: 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.
Comments.UserDisplayName: Bryan Redeagle
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2015-09-11T13:35:01.630Z
Comments.Text: 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.
Comments.UserDisplayName: Fyrebase
Tags: <templating><macro>
Title: Add / Update context from macro
ThreadText: # 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.
  
  ```
  <?php
  namespace Craft;
  
  class TwiggedTwigExtension extends \Twig_Extension
  {
    public function getName()
    {
      return 'Twigged';
    }
  
    public function getFunctions()
    {
      return array(
        'addVar' => 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:
  
  ```php
  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 @username_3. I've also tried passing it in by reference with the same result.  
  
  ---
  
  