marco Posted October 2, 2013 Share Posted October 2, 2013 Hi folks, I recently released the module Template Twig Replace that enables templating using the Twig engine instead of the default php/html templates. The module hooks into PageRender::___renderPage, replacing the original method and setting the Twig rendering results to the event's return property. I've taken a good amount of information from this post to achieve the results. Now I've discovered that pages will not be cached if the module is active. Some digging into the core (/wire/modules/PageRender.module) showed, that the method, I'm hooking not only renders a page but handles page caching (and some form of access control) as well. As a quick fix I duplicated the code handling cache files in my module to ensure pages a properly cached as usual. The fix is already commited to github and should be available in the module directory soon. This is would my module currently looks like: public function init() { // ... some more stuff .. // replace default page rendering by hooked method $this->addHookBefore('PageRender::renderPage', $this, 'renderPageWithTwig'); } /** * Hook callback for PageRender::renderPage * * Replaces default page rendering entirely. * * @param HookEvent $event The hook event * @throws WirePermissionException Page is not currently viewable. */ public function renderPageWithTwig(HookEvent $event) { $parentEvent = $event->arguments(0); // grab event provided to PageRender::renderPage // don't mess with admin templates $page = $parentEvent->object; if ($page->template == 'admin') return; // double check page's status // taken from PageRender::__render() if ($page->status >= Page::statusUnpublished && !$page->viewable()) { throw new WirePermissionException('Page \'' . $page->url . '\' is not currently viewable.'); } // forced replacing of default page rendering behaviour $event->replace = true; // look for cached data // taken from PageRender::__render() $options = count($parentEvent->arguments) ? $parentEvent->arguments[0] : array(); $defaultOptions = array( 'forceBuildCache' => false, ); $options = array_merge($defaultOptions, $options); $cacheAllowed = wire('modules')->get('PageRender')->isCacheAllowed($page); $cacheFile = null; if ($cacheAllowed) { $cacheFile = wire('modules')->get('PageRender')->getCacheFile($page); if(!$options['forceBuildCache'] && ($data = $cacheFile->get()) !== false) { $parentEvent->return = $data; return; } } // allow page fields to be accessed directly in Twig // e.g. {{ page.myfield }} instead of {{ page.get('myfield') }} Page::$issetHas = true; // render template $twigVars = $this->collectVariables($page->output); $output = $this->getTwig()->render($page->template->name . '.' . wire('config')->templateExtension, $twigVars); // cache output if possible // taken from PageRender::__render() if (!empty($output) && $cacheAllowed && !is_null($cacheFile)) $cacheFile->save($output); // manually set return of original event $parentEvent->return = $output; } But I think, the best option would be finding a hook the only renders a page's content and replacing this method. Is there a better hook to use that leaves handling page caching and maybe other pre- or post-processing alone and does template rendering only? Regards, Marco 1 Link to comment Share on other sites More sharing options...
Soma Posted October 2, 2013 Share Posted October 2, 2013 I'm not seeing through all this but have you seen this http://processwire.com/talk/topic/1421-twig/ ? Maybe something in there helpful? I'm not sure there's another method like you have now, but then I don't care about template engine anyway On a side note: "Instead of contaminating your template's and chunk's markup with php code, you would have the Twig templating syntax at hand." Should read: "Instead of using powerful ProcessWire template syntax code in your template's and chunk's markup, you would "contaminate" your templates with the Twig templating syntax." Sorry but just had to 3 Link to comment Share on other sites More sharing options...
ryan Posted October 12, 2013 Share Posted October 12, 2013 Marco, I think the hook you might be looking for would be TemplateFile::render. The only issue is that this is used by many things, like rendering of partials and such. So you'd probably want to hook into just the instance used by Page::render. Not tested, but I think you could do this by checking for the presence of the $options array (and better yet a property we know would be there--I'll use $options['pageStack']), which would indicate it's the instance you want: public function init() { $this->addHookAfter('TemplateFile::render', $this, 'hookRender'); } public function hookRender(HookEvent $event) { $templateFile = $event->object; $options = $templateFile->options; // checking for $options, which we know is given to page renders // this is to make sure it's not some other use of TemplateFile if(is_array($options) && array_key_exists('pageStack', $options)) { // this is a page render, go ahead and process the output $output = $event->return; $page = $templateFile->page; // I'm assuming you want this $output = yourTwigStuff($output $page); // replace with your Twig code $event->return = $output; } } Link to comment Share on other sites More sharing options...
tpr Posted February 13, 2016 Share Posted February 13, 2016 Is there any similar to check whether it is a wireRenderFile() call? $options may not available in that case, and I'm not sure checking for "$templateFile->filename" is suffice. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now