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.