nurkka Posted July 18, 2024 Share Posted July 18, 2024 I am using ProcessWire as the backend for an online shop system, which fetches the content as JSON files. The processwire installation has some legacy template code, which causes the startpage of the shop to require 3 or 4 actual ProcessWire pages. The JSON files are saved into a custom cache folder. When this cache is deleted, it has to be rebuilt. To achieve that, I implemented a Hook into PageRender::renderPage, which saves the currently viewed page and all of its language variants into JSON files. To get the actual markup, I am using $page->render(). Doing that, I noticed, that ProcessWire seems to prevent the currently requested page from also being generated (a second time) via $page->render(). The return value of $page->render() was always empty within the PageRender::renderPage Hook if $page was identical to the page of the current request. And it always returned the correctly rendered markup, if the current page was not identical to the Page in the $page->render() call. I assume that this has something to do with a mechanism in ProcessWire which shall prevent infinite loops. Does anybody know more about this? Are there any workarounds? Update: The issues were solved by cleaning up legacy template code – especially missing namespaces. Link to comment Share on other sites More sharing options...
poljpocket Posted July 24, 2024 Share Posted July 24, 2024 (edited) For me this sounds like a recursion loop. Why would you need to recursively call the render method again in the hook for said exact method? You can solve this for example by using an "after hook": <?php namespace ProcessWire; /** @var ProcessWire $wire */ $wire->addHookAfter('Page::render', function(HookEvent $event) { /** @var Page $page the page in question */ $page = $event->object; /** @var string $renderedMarkup the "after hook"'s return will contain the rendered page */ $renderedMarkup = $event->return; // ... do your stuff and use $renderedMarkup instead of a second call to render() as this would end up in a loop }); You can see something very similar in the PageRender docs here. To be completely honest, you should actually use the hook for when pages get saved because this is actually where the contents change. Using render for this sort of thing you are only wasting resources and re-writing the same markup again and again. Also, remember you don't need to reinvent caching. ProcessWire already has a full API for that! Edited July 24, 2024 by poljpocket clarify alternative approach using save hooks Link to comment Share on other sites More sharing options...
nurkka Posted July 24, 2024 Author Share Posted July 24, 2024 Thanks @poljpocket, you're right regarding the hook on Pages::saved, and I am already using that. But because of the nature of the online shop, which e.g. fetches up to four processwire pages per pageview, if I only use Pages::saved, in some cases, only one of those four pages will be up to date, when the others are outdated, until they are also saved. Which would never happen if it isn't done automatically. So, the perfect solution would be to determine the page ids of the other three pages, when saving one of those pages, and to render the JSON files of all those related pages. I am sure that is possible, but there are a lot of different cases, not only the described example. So I thought it would be a good idea, when processwire saved every page as JSON (additionally to displaying it as a normal page) when it is viewed - and of course every language variant (which is not viewed in the same request). To adress the issue with the same page not rendering twice: In the meantime, I found that the site had also a lot of templates without namespace. I corrected that, and now, the issue might have been gone. I am still testing that. Link to comment Share on other sites More sharing options...
poljpocket Posted July 24, 2024 Share Posted July 24, 2024 Another idea is to use ProcessWire's caching API and accomplish the JSON completely without the filesystem: use URL endpoints and cache the results until a page is saved. Ryan has used exactly your situation as an example of the (at the time) new feature "URL hooks". You can find that here: https://processwire.com/blog/posts/pw-3.0.173/#outputting-json-data-about-any-page-when-the-last-part-of-the-url-is-json. It is very easy to use a cached result in these hooks. You can find the API here: https://processwire.com/api/ref/wire-cache/. You can then use the Page::saved hook to clear the cache for a page's JSON. Link to comment Share on other sites More sharing options...
nurkka Posted July 24, 2024 Author Share Posted July 24, 2024 Thanks for your ideas! I have to automatically upload the generated JSON files to the shop server via SFTP. So, I think URL hooks and WireCache would not help in this case. After several hours of testing, I am now quite sure, that the original page saving problems resulted from the missing namespace in templates and includes. The problems didn't occur again. I am using the hooks ProcessPageView::finished and Pages::saved to generate the JSON-files, and that works for now. When testing, I had the impression that ProcessWire cached some of the includes, possibly because of the FileCompiler. Several times, changes in the code were not always immediately noticeable, but only after several reloads and/or a click on “Refresh” for the modules. I also tried the CacheControl module, to get rid of cached code. Perhaps this has something to do with the hosting and them caching php code, too ... but I don't know for sure. Anyway, the module now seems to work, at least for now. 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