4

I know Craft gives us access to Twigs getTwig template service; so when I attempt to use the addGlobal function like so:

craft()->templates->getTwig()->addGlobal('var', $var);

... nothing happens. No errors. I had hoped putting this in my plugins init() would allow me to call the variable in a twig template like so: {{ var }}. But that just returns an error.

Variable "var" does not exist

I know of other methods to define global variables. I just wondered where I was going wrong with that quick one-liner that doesn't seem to work.

Maybe Craft has ommitted it?

Thanks,

Mark

7

Edit: I needed to do a little digging.

Internally, Craft can actually have multiple instances of Twig_Environment running (a Twig_Environment instance is what you get back by calling craft()->templates->getTwig()). Craft caches each instance in a private class variable, with the template loader classname and a hash of the environment's options making up the cache key. If a Twig_Environment instance doesn't exist for the loader classname and options array you pass to getTwig() (null and null, in your case), Craft will actually create a new Twig_Environment instance and return it.

This means that you're probably not getting back the same Twig_Environment instance that Craft is using to actually render your template – which explains why the call to addGlobal() works, but the variable is still undefined in your template.

The solution is to make sure to pass in the same loader classname and options as Craft does, to make the TemplateService return the same instance. The default here appears to be null for the loader classname, and ['safe_mode' => false] for the options.

In other words, this should work:

public function init()
{
    $var = 'something';
    $twig = craft()->templates->getTwig(null, ['safe_mode' => false]);
    $twig->addGlobal('var', $var);
}

Unfortunately, I don't know if Craft can ever be expected to use different options (or even a different loader) in certain circumstances – e.g. if safe_mode would ever be true. In any case, it is false by default in the TemplatesService render() method. Hopefully, someone might clear this up further.

Anyway – for a less hacky way to add globals to the Twig environment, here's my original answer:

You'll need to create a custom Twig extension. In your extension class, add a getGlobals() method, e.g.

<?php namespace Craft;

use Twig_Extension;  
use Twig_Filter_Method;

class AwesomeTwigExtension extends \Twig_Extension  
{
    public function getName()
    {
        return 'Awesome';
    }
    public function getGlobals()
    {
        $var = 'something';
        return [
            'var' => $var,
        ];
    }
}

Don't forget to actually load your custom extension – in your plugin's primary class:

public function addTwigExtension()
{
    Craft::import('plugins.pluginhandle.twigextensions.AwesomeTwigExtension');
    return new AwesomeTwigExtension();
}

Of course, adding the globals in a custom extension instead of just using your plugin's primary class' init() method is a bit more verbose, but remember that you could easily add a method to your plugin's primary class returning the globals and just call that from your extension, e.g.

// In your plugin's primary class
public function getGlobals()
{
    $var = ...
    return [
        'var' => $var,
        ...
    ];
}

// In your custom Twig extension
public function getGlobals()
{
    return craft()->plugins->getPlugin('pluginHandle')->getGlobals();
}

(You could of course also return the globals from a plugin service, which would be cleaner).

Hopefully somebody else will have an explanation for why the addGlobal() method doesn't work – and perhaps an even easier solution.

  • Wow, now that's a comprehensive answer! Thank you for going into so much detail Mats. It would appear the 'less hacky' approach you mentioned is how I've been doing it already. I'm going to mark this as correct, because you have explained and demonstrated that getGlobal does exist and can be used, albeit with a few caveats. Thanks again, much appreciated. – Mark Notton Aug 24 '16 at 12:53
  • No worries, @MarkNotton - good to know it proved worthwhile. – Mats Mikkel Rummelhoff Aug 24 '16 at 13:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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