Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EVENT_AFTER_CREATE_TWIG #11774

Merged
merged 2 commits into from
Aug 12, 2022
Merged

EVENT_AFTER_CREATE_TWIG #11774

merged 2 commits into from
Aug 12, 2022

Conversation

brandonkelly
Copy link
Member

Adds an EVENT_AFTER_CREATE_TWIG event to craft\web\View::createTwig(), which can be called by plugins if they need to fire at the moment a Twig environment is created.

Since Craft creates separate Twig environments for control panel and site templates, the event class has a templateMode property which will either be set to cp or site depending on the active template mode, in case it’s relevant to the handler.

use craft\events\CreateTwigEvent;
use craft\web\View;
use yii\base\Event;

Event::on(
    View::class,
    View::EVENT_AFTER_CREATE_TWIG,
    function(CreateTwigEvent $event) {
        if ($event->templateMode === View::TEMPLATE_MODE_SITE) {
            $event->twig->addGlobal('myGlobalVariable', 'foo');
        }
    }
);

@brandonkelly brandonkelly requested a review from a team as a code owner August 12, 2022 17:59
[ci skip]
@brandonkelly brandonkelly merged commit 5e632ec into 4.3 Aug 12, 2022
@brandonkelly brandonkelly deleted the feature/create-twig-event branch August 12, 2022 18:01
@khalwat
Copy link
Contributor

khalwat commented Jul 4, 2024

So this is great except for one small thing... this sequence of code:

        // Set our timezone
        /** @var CoreExtension $core */
        $core = $twig->getExtension(CoreExtension::class);
        $core->setTimezone(Craft::$app->getTimeZone());

        // Fire an 'afterCreateTwig' event
        if ($this->hasEventHandlers(self::EVENT_AFTER_CREATE_TWIG)) {
            $this->trigger(self::EVENT_AFTER_CREATE_TWIG, new CreateTwigEvent([
                'templateMode' => $this->_templateMode ?? self::TEMPLATE_MODE_SITE,
                'twig' => $twig,
            ]));
        }

...doesn't allow an event listener to add extensions to Twig, because the call to $twig->getExtension() initializes Twig, so an exception is thrown if you try to add a Twig extension inside of the event handler or do something else that wants to modify the Twig environment.

You might want to change the event sequence to be:

        // Fire an 'afterCreateTwig' event
        if ($this->hasEventHandlers(self::EVENT_AFTER_CREATE_TWIG)) {
            $this->trigger(self::EVENT_AFTER_CREATE_TWIG, new CreateTwigEvent([
                'templateMode' => $this->_templateMode ?? self::TEMPLATE_MODE_SITE,
                'twig' => $twig,
            ]));
        // Set our timezone
        /** @var CoreExtension $core */
        $core = $twig->getExtension(CoreExtension::class);
        $core->setTimezone(Craft::$app->getTimeZone());
        }

@brandonkelly
Copy link
Member Author

To register Twig extensions, you should be using Craft::$app->view->registerTwigExtension(), which will ensure the extension gets included when Twig is initialized. (And if Twig is already initialized, it will discard the existing instance.)

@khalwat
Copy link
Contributor

khalwat commented Jul 30, 2024

Right, but even if we added the extension that way via the EVENT_AFTER_CREATE_TWIG event, for the reasons I mentioned above, it would fail because the Twig environment has been initialized already.

Twig lazily initializes itself if $twig->getExtension() is called... so moving the event up before you call that would allow an uninitialized Twig to be modified by the event.

Without that, there really isn't much that can be done in that event callback in terms of modifying the Twig environment before Craft uses it.

@khalwat
Copy link
Contributor

khalwat commented Jul 30, 2024

Okay I looked at the code for View::registerTwigExtension() and see what you mean, in that it will null out the appropriate Twig environment (which causes it to be recreated later).

So for this specific thing, yes, that's a workable solution. There are other ways you might want to modify the Twig environment that it still might be useful to move the event to before Twig gets initialized, IMO, but up to you.

khalwat added a commit to nystudio107/craft-closure that referenced this pull request Jul 31, 2024
…_CREATE_TWIG` to hook Closure in, so it will work with any Craft-created Twig environment (not just when rendering page templates) ([#11774](craftcms/cms#11774))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants