Ivan Gretsky Posted September 17, 2020 Share Posted September 17, 2020 Good day! I am trying to do a frontend check in a Page::render hook and return completely different markup on condition: <?php // This is site/ready.php wire()->addHookAfter('Page::render', function (HookEvent $event) { $page = $event->object; ... //Some condition here $config = wire("config"); $t = new ProcessWire\TemplateFile($config->paths->templates . "test.php"); $t->setArray(array( 'page' => wire()->pages->get("1234"), ) ); $t->setPrependFilename($config->paths->templates . '_init.php'); $t->setAppendFilename($config->paths->templates . '_main.php'); $out = $t->render(); $event->return = $out; } But I get this error: Cannot redeclare SomeFubction() (previously declared in ...\site\templates\_func.php:123) _func.php is included with include_once in _init.php. But somehow _init.php happens to run twice. Can't get my head around this one. Please help! Link to comment Share on other sites More sharing options...
horst Posted September 17, 2020 Share Posted September 17, 2020 Maybe this does not work (I'm on mobile), but have you tried to set a var in _init.php like this: if(isset($alreadyExecuted) && $alreadyExecuted) return; $alreadyExecuted = true; // set it in the first run. EDIT: Or bind the include of _functions.php on the condition of the var. 1 Link to comment Share on other sites More sharing options...
Ivan Gretsky Posted September 17, 2020 Author Share Posted September 17, 2020 I did put this in _init.php: <?php namespace ProcessWire; bd("inside init"); bd($alreadyExecuted, '$alreadyExecuted'); if(isset($alreadyExecuted) && $alreadyExecuted) return; $alreadyExecuted = true; // set it in the first run. bd("inside init 2"); And here's what I get: Link to comment Share on other sites More sharing options...
horst Posted September 17, 2020 Share Posted September 17, 2020 Ok, maybe scoping is what is in the way. Try setting as $GLOBALS["alreadyExecuted"]. 1 Link to comment Share on other sites More sharing options...
Ivan Gretsky Posted September 18, 2020 Author Share Posted September 18, 2020 Changing the condition to use a super global variable indeed helped me to prevent _init.php from running once again. But in this case the TemplateFile object doesn't get any variables from _init.php which it need to render correctly. I thought, that I need to move all the code to another hook before the Page:render. So I made PageRender::beforeRenderPage hookable and moved the code there. But that still didn't work. I am definitely lost here(( Link to comment Share on other sites More sharing options...
horst Posted September 18, 2020 Share Posted September 18, 2020 Let all your code you need to run twice in the root of _init.php. Wrap all other, like the include_once of the _functions.php into a superglobal var condition, or, if the include of the _functions.php is the only issue you have, you can wrap this in a condition with function_exists: if(!function_exists("aFunctionNameThatExistsInFunctionsPhp")) include(__DIR__ . "/_functions.php"); Link to comment Share on other sites More sharing options...
Ivan Gretsky Posted September 18, 2020 Author Share Posted September 18, 2020 Those functions are needed in _main.php to render correctly. I think there must be some better solution. If I run $page->render() in the same hook, it works fine. Though it obviously also load both _init.php and _main.php on the way. Link to comment Share on other sites More sharing options...
Zeka Posted September 18, 2020 Share Posted September 18, 2020 @Ivan Gretsky I am not sure that this will help, but for one project I been using these hooks for a similar task. Maybe it will give you some ideas. public function init() { $this->addHookBefore('PageRender::renderPage', $this, 'hookBeforePageRenderTemplater'); $this->addHookAfter('TemplateFile::render', $this, 'hookAfterTemplateRender'); $this->wire('config')->ignoreTemplateFileRegex = "/(\.before\.)|(\.after\.)|(\.{$this->template_files_suffix}\.)|(^_)/"; } public function hookBeforePageRenderTemplater($e) { $event = $e->arguments(0); $page = $event->object; if ($page->template->name == 'admin') return; $options = $event->arguments(0); $template = $page->template; $options['prependFiles'] = [ "{$template}.before.php", "_init.php", ]; $options['appendFiles'] = [ "{$template}.after.php", "_after.php", ]; $event->setArgument(0, $options); } public function hookAfterTemplateRender($event) { if ($this->wire('page') == null) return; if (strpos($event->object->filename, 'TracyDebugger') !== false) return; if (str_replace('site/assets/cache/FileCompiler/', '', $event->object->filename) !== $this->wire('page')->template->filename) return; if (strpos($_SERVER['REQUEST_URI'], $this->wire('config')->urls->admin) === 0 || $this->wire('page')->template->name == 'admin') return; $template = $event->object; $options = $template->options; if (is_array($options) && array_key_exists('pageStack', $options)) { $view = $this->wire($this->api_view_var); $layout = $this->wire($this->api_layout_var); $page = $this->wire('page'); $page_template = $page->template; if ($template->halt) { return; }; if (empty($options['pageStack']) && $page_template->templater_url_segments) $this->wire('session')->redirect($page->url); $template_name = ($page->template->altFilename) ? $page->template->altFilename : $page->template->name; $view_file = $this->getViewFilePath($template_name); if (is_file($view_file)) { $view->setFilename($view_file); } else { throw new WireException("View file for this page template ({$view_file}) does not exist"); } $event->return = $event->return . $layout->render(); } } 2 Link to comment Share on other sites More sharing options...
Zeka Posted September 18, 2020 Share Posted September 18, 2020 I don't remember why there are all these checks in hookAfterTemplateRender, but in such way it could identify a template that was used for rendering of the current page 2 Link to comment Share on other sites More sharing options...
Ivan Gretsky Posted September 27, 2020 Author Share Posted September 27, 2020 I've solved the issue. The problem was that I was hooking the wrong method. I've adopted the code from this post and everything started working properly. 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