DrQuincy Posted May 14, 2021 Share Posted May 14, 2021 I need to check some data when pages are moved or saved. It runs fine when I save a page (Pages::saved) but nothing happens when I move a page (e.g. to and from trash). It only appears to be the lack of warning that is the issue. The hook definitely runs when I move pages in the site tree as I set up a simple bit of text file logging. wire()->addHookAfter('Pages::moved, Pages::saved', function($event) { $event->warning('Warning'); }); Is it because from the site tree moving pages is done with AJAX? Is there a way to output a warning when sorting or moving pages in the site tree or is it not possible? Thanks. P.S. I have noticed on Pages::saved if you change the status from the tree view (using Unpub, Hide buttons) the hook calls but the messages are not displayed. So really I guess my question is: how can hooks send messages, errors and warnings in the tree view? Link to comment Share on other sites More sharing options...
Robin S Posted May 15, 2021 Share Posted May 15, 2021 On 5/14/2021 at 7:26 PM, DrQuincy said: So really I guess my question is: how can hooks send messages, errors and warnings in the tree view? There's no simple way to do this because when a page is moved the page list is updated via AJAX, whereas the core message() / warning() / error() methods require a normal page load in order to appear. But I had fun exploring some workarounds. Maybe one of these will suit or maybe not. In these examples a message is shown whenever a page is moved but of course you would add your own logic show your message more selectively. Option 1: queue a warning() to appear at the next page load via $session->warning(), and use some JS to automatically reload ProcessPageList whenever a page is sorted or moved. In some custom admin JS (you can add this with a hook or by using AdminOnSteroids): // When a page is moved in ProcessPageList $(document).on('pageMoved', '.PageListItem', function() { // Reload location.reload(); }); In /site/ready.php // When a page is moved $wire->addHookAfter('Pages::moved', function(HookEvent $event) { $page = $event->arguments(0); // Show a warning $event->wire()->session->warning("Page '{$page->title}' was moved to parent '{$page->parent->title}'."); }); Result: Option 2: Make use of the fact that when an exception is thrown ProcessPageList will show this as an alert. The below assumes that you only want to show a warning when a page is moved to a new parent and not when it is sorted within its existing parent. If that distinction doesn't matter then you could simplify this by only hooking after ProcessPageSort::execute(). In /site/ready.php // Optional: use Vex for nicer alerts in ProcessPageList $wire->addHookBefore('ProcessPageList::execute', function(HookEvent $event) { $event->wire()->modules->get('JqueryUI')->use('vex'); }); // Before ProcessPageSort::execute $wire->addHookBefore('ProcessPageSort::execute', function(HookEvent $event) { $pps = $event->object; $move_id = (int) $event->wire()->input->post->id; $moved = $event->wire()->pages->get($move_id); // Store original parent ID on the ProcessPageSort object $pps->original_parent_id = $moved->parent->id; }); // After ProcessPageSort::execute $wire->addHookAfter('ProcessPageSort::execute', function(HookEvent $event) { $pps = $event->object; $input = $event->wire()->input; $pages = $event->wire()->pages; $parent_id = (int) $input->post->parent_id; $move_id = (int) $input->post->id; $parent = $pages->get($parent_id); $moved = $pages->get($move_id); // Check if the parent ID has changed from the original (i.e. the page has moved) if($parent->id !== $pps->original_parent_id) { // Show an alert by making use of how exceptions are handled in ProcessPageList throw new WireException("Page '{$moved->title}' was moved to parent '{$parent->title}'."); } }); Result: Option 3: do it all in JavaScript. Whether this is viable depends on what sort of logic you need. With a bit of extra faffing around (not shown here) you can get things like the page IDs and template names from the class names of the page list items which might help. Optionally add the Vex library as in option 2. And then in some custom admin JS: // When a page is moved in ProcessPageList $(document).on('pageMoved', '.PageListItem', function() { var moved_title = $(this).find('.label_title').text(); var $parent = $(this).parent('.PageList').prev('.PageListItem'); var parent_title = $parent.find('.label_title').text(); var $from = $('#PageListMoveFrom').prev('.PageListItem'); if($from.length) { // Page was moved to a different parent var from_title = $from.find('.label_title').text(); ProcessWire.alert('Page "' + moved_title + '" was moved to parent "' + parent_title + '" from parent "' + from_title + '"'); } else { // Page was sorted within its existing parent ProcessWire.alert('Page "' + moved_title + '" was sorted within parent "' + parent_title + '"'); } }); Result: 9 Link to comment Share on other sites More sharing options...
DrQuincy Posted May 17, 2021 Author Share Posted May 17, 2021 Wow, thanks @Robin S, I was not expecting such detailed examples! Thanks so much for the effort you have put in. I'll have a think about it this week as to the best way to do what I want but you have given me some excellent starting points. ? 1 Link to comment Share on other sites More sharing options...
DrQuincy Posted May 18, 2021 Author Share Posted May 18, 2021 @Robin S Thanks again, this has been extremely helpful. I think if I use Pages::saved and ProcessPageSort::execute per your example it should cover everything I need (I am detecting non-unique values in pages/templates mimicking a database unique index). Pages::saved can be called in the site tree (AJAX) or via a standard POST when editing a page (changing status from the site tree calls this) — or even the API. As you have demonstrated if using AJAX then throwing an Exception can do the job. However, I would rather output a warning if a standard POST request and only use Vex/Exception if AJAX as the former is more flexible. If there any way in the Pages::saved hook to know whether it is an AJAX call or not? Is there a property in the API or do I just have to check the $_SERVER['REQUEST_PATH'] or something? Thank you! Link to comment Share on other sites More sharing options...
Robin S Posted May 18, 2021 Share Posted May 18, 2021 6 hours ago, DrQuincy said: If there any way in the Pages::saved hook to know whether it is an AJAX call or not? Yes, $config->ajax will be true if the current request is AJAX. 1 Link to comment Share on other sites More sharing options...
DrQuincy Posted May 19, 2021 Author Share Posted May 19, 2021 Fantastic, thank you. You have been a huge help! 1 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