In Page.php we have the hookable loaded method:
/**
* For hooks to listen to, triggered when page is loaded and ready
*
* #pw-hooker
*
*/
public function ___loaded() { }
It is called on these spots in PW:
So this means that loaded() is triggerd on a page find operation:
I'm not 100% sure if that means that it is called on every page find or if PW's internal cache somehow plays a role, but as long as the page is not loaded, the loaded hook will not trigger.
If you look at the docs of modules you see that init() is called immediately when the module is loaded and ready() is called when the api is ready. This can make an important difference sometimes where hooks work in init() but not in ready() and vice versa.
Page objects don't have these methods though. These are all the hookable methods of the Page baseclass:
Additionally you have hookable methods in PagePermissions.module:
And several others ?
But no init() and ready(). Because init() and ready() are a concept of PW modules:
My point is that loaded() of a page might only be triggered in very special cases. Imagine a module that loads a page only on uninstall() of the module. Then the loaded() event of your pageClass would happen very late in the request. But if you use custom page classes in an object oriented way then they become much more like a PW module and then I think it makes sense to stick to the PW module naming convention and that means that init() is triggered on module/pageclass init - just like you had the code in init.php. That IMHO does also mean, that this code does get executed on EVERY request.
It does NOT mean, that the code is executed only ONCE - that's a matter of the "singular" setting of a module. See examples below.
Code in ready() on the other hand is just like code in ready.php - it fires once, but later in the process, when the API is ready and all other init() methods of all modules and pageclasses have been triggered.
Try this /site/modules/Test.module.php
<?php namespace ProcessWire;
class Test extends WireData implements Module {
public static function getModuleInfo() {
return [
'title' => 'Test',
'version' => '0.0.1',
'summary' => 'Your module description',
'autoload' => false,
'singular' => false,
'icon' => 'smile-o',
'requires' => [],
'installs' => [],
];
}
public function init() {
bd('test init');
}
public function ready() {
bd('test ready');
}
}
Install the module and then call it from the tracy console:
It only fires init() but not ready() - because when loading the module PW's ready event has already been triggered.
Now make that module autoload, do a modules refresh and fire the console code again:
You see the difference? ?
Now just for fun we make the module "singular":
If I happen to need something to execute on every load of the pageClass I use the class constructor:
This means that my custom pageclass always has the correct template and does always live under the correct parent in the pagetree.
As you can see I define all my fields as class constants. This makes the code so much more readable and also makes typos nearly impossible. It might feel like overhead, but actually it makes me a lot more efficient as well:
So I'm actually using most if not all of my page classes as something like a singular autoload module. Overhead? Maybe a little. Problem? I think/hope no ?
Hope that helps. Suggestions for improving this further always welcome ?