Juergen Posted January 29 Share Posted January 29 Hello @all I have tried to apply a hook to a class of a module of my mine which runs inside a namespace. The hook is included inside the site/init.php. $this->wire()->addHookAfter('Label::renderAsterisk', function(HookEvent $event) { bd('render Asterisk'); }); This hook runs on the function renderAsterisk() which is hookable and part of the class "Label" (original File: Label.php). This class descends from Wire so hooks should work inside this class, but I guess the main problem is that this class runs inside its own namespace called "FrontendForms". So I tried different versions within the hook to define the class: FrontendForms\Label::renderAsterisk \FrontendForms\Label::renderAsterisk \\FrontendForms\Label::renderAsterisk FrontendForms\\Label::renderAsterisk None of the versions above work! After a search on the internet, I found a discussion about this problem here. It seems that other people have also stumbled upon this problem. My question: Has anyone already struggled with the same problem and found a solution on how to get hooks to work on classes with namespaces, or could there be another cause responsible for this behavior? Additional info: This issue comes from my FrontendForms module and I've used hooks in the past to manipulate the output a bit (look here). The hooks have worked in the past, but it seems that they don't work anymore in PW version 3. Thanks for your help! Link to comment Share on other sites More sharing options...
bernhard Posted January 29 Share Posted January 29 I'm using namespaces all the time and it works for me when not adding the namespace on the hook. 1 Link to comment Share on other sites More sharing options...
Juergen Posted January 29 Author Share Posted January 29 Hello @bernhard This is interesting, but in my case the hook does not get fired. It seems that that it will be ignored. The function is hookable by prefixing 3 underscores: public function ___renderAsterisk(): string { return '<span class="asterisk">*</span>'; } The class 'Label' itself (where the function above is part of) is derived from the Wire class (take a look here on the top parent class), so hooks must be implemented and should work. Only to mention: the top parent class called 'Tag' is an abstract class - could this have an impact on the issue? Do you have a working example in one of your numerous modules, where you use a hook inside the init.php to hook a method in one of your modules? Link to comment Share on other sites More sharing options...
bernhard Posted January 29 Share Posted January 29 /site/init.php wire()->addHookAfter('Foo::hello', function ($event) { $event->return .= ' - hooked :)'; }); /site/modules/WhatEver/Test.module.php <?php namespace ProcessWire; use MyNamespace\Foo; class Test extends WireData implements Module { public static function getModuleInfo() { return [ 'title' => 'Test', 'version' => '0.0.1', 'summary' => 'Your module description', 'autoload' => true, 'singular' => true, 'icon' => 'smile-o', 'requires' => [], 'installs' => [], ]; } public function init() { wire()->classLoader->addNamespace('MyNamespace', __DIR__ . '/classes'); } public function ready() { $foo = new Foo(); bd($foo->hello()); } } /site/modules/WhatEver/classes/Foo.php <?php namespace MyNamespace; use ProcessWire\Wire; class Foo extends Wire { public function ___hello() { return "HELLO!"; } } 2 Link to comment Share on other sites More sharing options...
Juergen Posted January 29 Author Share Posted January 29 Thanks for your quick response @bernhard I compared your example to mine and I see that you are calling the method ($foo->hello()) inside your ready() method. In this case it works on my side too, but this is not the scenario that I want. I want to manipulate the output not inside the ready() but before page render, so the markup of the method should be changed before the page will be rendered. public function ___renderAsterisk(): string { return '<span class="asterisk">*</span>'; } This is a render function, which will be called during the render function of the form and the form will be rendered during the page will be rendered. So I want to change the output of the renderAsterisk() method inside the site/init.php and this does not work at all. wire()->addHookAfter('Label::renderAsterisk', function ($event) { $event->return = ' - hooked aha :)'; }); So this works fine if the renderAsterisk() method will be called inside the ready.php separately. $foo = new Label(); bd($foo->renderAsterisk()); But it does not work if the renderAsterisk() method is included inside another render function (in this case inside the render function of the form. This should be the issue of the problem. To simplify: It works if the renderAsterisk() method will be called directly, but not if this method is included within another method and will be called there. 1 Link to comment Share on other sites More sharing options...
Juergen Posted January 30 Author Share Posted January 30 Conclusion: It is not possible to hook a class that is not loaded directly on a page. In my case, the Label class is loaded and used indirectly within the form, as it is used within the inputfield class and not directly in the form class. The form class is loaded directly onto the page and can be hooked - the Label class is not. Link to comment Share on other sites More sharing options...
bernhard Posted January 30 Share Posted January 30 I'd be interested, but I don't understand what you are saying. Neither what you said yesterday nor what you said today. What is "a class loaded directly on a page"? And what is "indirectly within a form" ?! Link to comment Share on other sites More sharing options...
bernhard Posted January 30 Share Posted January 30 On 1/29/2025 at 5:08 PM, Juergen said: I want to manipulate the output not inside the ready() but before page render Expand It should not matter when/where you do it. The only thing that matters is that you attach your hook before you actually call the method that is hooked. If you call the method first and than add the hook it will obviously not return the hooked result but the plain result. Link to comment Share on other sites More sharing options...
Juergen Posted January 30 Author Share Posted January 30 It is a little bit difficult to explain: Direct call of a class method on a page: $form = new Form(); echo $form->render(); The method will be called directly on a page, so hooking Form::render works. Direct call of a method of another class inside a method on a page: public function ___render() { $out = ''; $object = new Element(); $out .= $object->renderElement(); return $out; } As you can see the method renderElement of the class Element will be called inside the render method of the Form class so Element::renderElement is hookable too. The problem occurs if a method of the Element class should be hooked that is not directly called inside the given renderElement() method. class Element { public function ___test() { return 'Test'; } public function ___renderElement{ return 'Element'; } } So if you want to hook Element::test it will not be triggered, because it will not executed inside the renderElement() method. That was my experience with the hook problem Link to comment Share on other sites More sharing options...
Robin S Posted January 30 Share Posted January 30 I didn't read this thread closely but I see you are calling $this->___renderAsterisk() https://github.com/juergenweb/FrontendForms/blob/9ea92a986528a96e2aeb875482967b81e8a50018/Formelements/Textelements/Label.php#L59 If you want hooks to fire you need to call it without the underscores: $this->renderAsterisk() 2 Link to comment Share on other sites More sharing options...
Juergen Posted January 31 Author Share Posted January 31 On 1/30/2025 at 10:09 PM, Robin S said: If you want hooks to fire you need to call it without the underscores: $this->renderAsterisk() Expand This could be the possible reason for the strange behavior. I will try it! Thank you so much!! 🙂 Link to comment Share on other sites More sharing options...
Juergen Posted January 31 Author Share Posted January 31 I have tried it and now it is working well on my localhost!!!! I will test it on a live site too, but it should work there too. Thank you!!!!! 1 Link to comment Share on other sites More sharing options...
Robin S Posted January 31 Share Posted January 31 Here is the relevant part of the docs for reference: https://processwire.com/docs/modules/hooks/#how-can-i-define-my-own-hookable-methods Quote Calls to a hookable method should always be without the 3 underscores, i.e. $this->hookableMethod('a', 'b'); If for some reason you need to bypass ProcessWire's hook system for a given method, you can include the 3 underscores in the method call and no hooks will be executed. Expand 1 Link to comment Share on other sites More sharing options...
Juergen Posted January 31 Author Share Posted January 31 How can I miss that - I've always overlooked that! Thanks for the relevant information - this will save me a lot of time and troubles in the future.🙂 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