LAPS Posted August 2, 2022 Share Posted August 2, 2022 Hello, I'm implementing the third conditional hook example here (the one that "taken a little further on the implementation side"), but for the User and Users classes. Sadly, I cannot make it to work. In fact, the following code does log only the message "running in main hook". In my ready.php file, with primitive debugging, I've: wire()->addHookAfter("User::changed(user_bookmarks)", function(HookEvent $event) { $user = $event->object; // User $old = $event->arguments(1); // old value $new = $event->arguments(2); // new value wire('log')->message("running in main hook"); // debug01 $event->addHookAfter("Users::saved($user)", function($event) use($user, $old, $new) { wire('log')->message("debug01"); $event->removeHook(null); }); // debug02 $event->addHookAfter("Users::save($user)", function($event) use($user, $old, $new) { wire('log')->message("debug02"); $event->removeHook(null); }); // debug03 $event->addHookAfter("User($user)::saved", function($event) use($user, $old, $new) { wire('log')->message("debug03"); $event->removeHook(null); }); // debug04 $event->addHookAfter("User($user)::save", function($event) use($user, $old, $new) { wire('log')->message("debug04"); $event->removeHook(null); }); }); In a template.php file, I modify the $user like this: // ... $user_bookmarks = $user->getUnformatted('user_bookmarks'); // ... $user_bookmarks->add($a_page); $user_bookmarks->remove($another_page); // ... $user->setAndSave('user_bookmarks', $user_bookmarks); Since by successfully running setAndSave() no one of the above-mentioned debug messages gets logged, no one hook gets triggered. How can I properly make those hooks to be triggered? I would like to take some actions each time the user's user_bookmarks field get updated. Link to comment Share on other sites More sharing options...
Jan Romero Posted August 2, 2022 Share Posted August 2, 2022 I think you fell victim to one of the classic blunders. SetAndSave() specifically only saves a particular field, and field-saves don’t trigger the saved() hook. Check out savedPageOrField() to catch both types of save operation: https://processwire.com/api/ref/pages/saved-page-or-field Link to comment Share on other sites More sharing options...
LAPS Posted August 2, 2022 Author Share Posted August 2, 2022 Thanks @Jan Romero. I'm experimenting with the savedPageOrField hook to limit it to run for user pages (because I'm working on Users), and I report this: // ready.php wire()->addHookAfter("Pages::savedPageOrField", function($event) { ... // does work wire()->addHookAfter("Page(template=user)::savedPageOrField", function($event) { ... // does not work wire()->addHookAfter("Pages(template=user)::savedPageOrField", function($event) { ... // does not work wire()->addHookAfter("User::savedPageOrField", function($event) { ... // does not work wire()->addHookAfter("Users::savedPageOrField", function($event) { ... // does not work // template.php // ... $user->setAndSave('user_bookmarks', $user_bookmarks); A say in the PW community is "users are pages too", so I expect hooks to work with Users as they work with Pages. Am I going to be victim of another of the classic blunders? ? Any help about achieving with hooks (even the savedPageOrField one) the goal to take custom actions each time the user's user_bookmarks field get updated? Link to comment Share on other sites More sharing options...
Jan Romero Posted August 2, 2022 Share Posted August 2, 2022 Hi, this works for me: wire()->addHookAfter("User::changed(user_bookmarks)", function(HookEvent $event) { $user = $event->object; // User $old = $event->arguments(1); // old value $new = $event->arguments(2); // new value wire()->addHookAfter("Pages::savedPageOrField($user)", function(HookEvent $event) use($user, $old, $new) { var_dump($user); var_dump($old); var_dump($new); var_dump($event); }); }); Btw there is also savePageOrFieldReady(). Might be of interest if you want to modify the user. 1 Link to comment Share on other sites More sharing options...
LAPS Posted August 2, 2022 Author Share Posted August 2, 2022 3 minutes ago, Jan Romero said: this works for me For me too ? ? 1 Link to comment Share on other sites More sharing options...
LAPS Posted August 2, 2022 Author Share Posted August 2, 2022 @Jan Romero I was too fast to say that worked for me. The log files seem gone crazy receiving many entries! ? ? Probably, it's because within the Pages::savedPageOrField($user) hook function I'm updating other $user fields, which causes the infinite loop. In fact, if I don't update the $user within savedPageOrField($user), the whole hook subtly works. I think the problem is related to the Pages::savedPageOrField($user) hook and I'm trying to limit the run of this hook by passing someway the second argument $changes... // usage with all arguments $pages->savedPageOrField(Page $page, array $changes = []); ... something like made in the official docs by using changed(0:order_status, 1:name=pending, 2:...) // ??? = what? how to state the $changes array? wire()->addHookAfter("Pages::savedPageOrField(0:$user, 1:???)", function(HookEvent $event) use($user, $old, $new) { ... and by setting limiting conditions the more classic way wire()->addHookAfter("User::changed(user_bookmarks)", function(HookEvent $event) { // ... wire()->addHookAfter("Pages::savedPageOrField($user)", function(HookEvent $event) use($user, $old, $new) { // if something, exit now ??? // ... Any help is appreciated. Link to comment Share on other sites More sharing options...
Jan Romero Posted August 2, 2022 Share Posted August 2, 2022 Do you specifically need to use that nested hooks technique? If you want to update related user fields when a specific field is about to be saved, you can just hook savePageOrFieldReady() and evaluate the changes: wire()->addHookAfter("Pages::savePageOrFieldReady(template=user)", function(HookEvent $event) { $user = $event->arguments(0); if (!$user->isChanged('user_bookmarks')) return; //bookmarks weren’t changed, nothing to do $user->of(false); $user->set('title', 'that user who keeps changing their bookmarks'); }); Note you don’t need to call save() or anything, you’re piggybacking off of the hooked save operation. <-- doesn’t work if the hook was triggered by a field save. Otherwise, did you remove the nested hook according to the example in the docs? Link to comment Share on other sites More sharing options...
LAPS Posted August 2, 2022 Author Share Posted August 2, 2022 @Jan Romero I used your code and some other weird functions to come up with a solution, without success. 2 hours ago, Jan Romero said: wire()->addHookAfter("Pages::savePageOrFieldReady(template=user)", function(HookEvent $event) { $user = $event->arguments(0); if (!$user->isChanged('user_bookmarks')) return; //bookmarks weren’t changed, nothing to do $user->of(false); $user->set('title', 'that user who keeps changing their bookmarks'); }); It seems ignoring all-known-to-me $user->set('title', '...')-like functions for saving the user. User changes (except user_bookmarks) are not saved after the process ends. Link to comment Share on other sites More sharing options...
Jan Romero Posted August 2, 2022 Share Posted August 2, 2022 Yeah, you’re right, the piggybacking I mentioned only works with full page saves… Guess you’ll have to call save() after all. You can do so by specifying the noHooks option, so that you don’t call your hook infinite times: $user->setAndSave('title', 'that user who keeps changing their bookmarks', ['noHooks' => true]); You can also hook savedPageOrField(), in which case the names of the changed fields will be in $event->arguments(1). Link to comment Share on other sites More sharing options...
LAPS Posted August 2, 2022 Author Share Posted August 2, 2022 By using ['noHooks' => true] I still run into trouble.. and the hook runs between 3-8000+ times (var_dump, log, etc.)! wire()->addHookAfter("User::changed(user_bookmarks)", function(HookEvent $event) { // ... // here something that handles the following hook creation or updating and that avoids running into infinite loop // ... wire()->addHookAfter("Pages::savedPageOrField($user)", function(HookEvent $event) use($user, $old, $new) { // here something that save $user // $user->save() or $user->setAndSave() with $options ['noHooks' => true] // ... $event->removeHook(null); 19 hours ago, Jan Romero said: You can also hook savedPageOrField(), in which case the names of the changed fields will be in $event->arguments(1). Do you mean to use the savedPageOrField() hook "standalone"? Or "nested" within another hook as in the above code? 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