Ok, sorry, clickbait ? Hooks are great! But sometimes, there are even better solutions:
I'm cleaning up RockForms to finally release it ? I have some pages that are only for storing data (like form entries and such), so I don't want them to be editable, not even for superusers, as I control them solely via code in my module.
-- Solution 1 --
With a regular hook that would look like this:
<?php
// site/ready.php
$wire->addHookAfter("Page::editable", function($event) {
$page = $event->object;
if($page instanceof \RockForms\Root) $event->return = false;
});
That's quite nice, but this approach has some drawbacks: First, sooner or later you might end up with hook-hell in ready.php; That's not ideal and really hard to debug on more complex projects. Second, as we are defining the hook with a callback in a non-OOP style these hooks get a LOT harder to debug!
Have a look at tracy's debug panel:
The second highlighted hook is the one coming from ready.php and it does not show any helpful information whereas the first one does show clearly that the hook is attached in RockForms\Root in the method "hookUneditEntries" (it should be hookUneditRoot, but I made a mistake when copy-pasting, sorry ? ).
-- Solution 2 --
So the next best solution IMHO is using custom page classes! Then you get OOP style and a lot better structure for your project with really very little effort! Just create a file in /site/classes and that's it.
Now to attach hooks directly in custom page classes you have to do one additional step. You can watch my video about this if you are interested. If not, head over to solution number 3 which is even simpler ?
This solution might look something like this:
<?php
namespace RockForms;
use ProcessWire\HookEvent;
use ProcessWire\Page;
use RockMigrations\MagicPage;
use function ProcessWire\wire;
class Root extends Page
{
use MagicPage;
public function init()
{
wire()->addHookAfter("Page::editable", $this, "hookUneditRoot");
}
protected function hookUneditRoot(HookEvent $event): void
{
$page = $event->object;
if (!$page instanceof self) return;
$event->return = false;
}
}
This might look like a lot more code, but it's a lot better in the long run in my opinion as things that are related solely to the root page are inside the Root.php file of my module/project.
-- Solution 3 --
But then I remembered: As our "Root"-page is a custom page class and PW checks if the page is editable or not by calling $page->editable() we can simply override this method like so:
<?php
namespace RockForms;
use ProcessWire\Page;
class Root extends Page
{
public function editable() {
return false;
}
}
You don't even need to make it a "MagicPage" because you don't need an init() method to attach any hooks.
Now it's only very little additional code compared to a hook in ready.php but with a lot cleaner setup ?
It's not a new invention, but I thought I'd share it nevertheless. Maybe it's helpful for some and maybe it's a good reminder for others, that even hooks are sometimes "overkill" ?