Pete Posted November 26, 2013 Share Posted November 26, 2013 I've got a requirement to prevent a page being trashed or deleted and instead hidden and show a message. Essentially what I want to do is, for given templates, prevent anyone from being able to delete the pages. A reasonably common example of this would be in e-commerce where you would never want to allow a product to be deleted if it has ever been ordered, otherwise the order details page would break (there is an argument there for storing a JSON array of ordered products in case the name ever changes, but we won't go into that just yet ). What I want to do is something like this: public function ready() { $this->pages->addHookBefore('trash', $this, 'preservePages'); $this->pages->addHookBefore('delete', $this, 'preservePages'); } public function preservePages(HookEvent $event) { $page = $event->arguments[0]; if ($this->page->template = 'template-name') { $page->addStatus(Page::statusHidden); $this->message('Page has been hidden instead of deleted - need to work on the wording'); // Then some way of stopping the trash or delete methods runnning, but can't think of what would work here return false; } } Any ideas? Oh, and I don't want to do it with access control for some reason I can't remember right now. That would be easy as I could just prevent users being able to delete the page Link to comment Share on other sites More sharing options...
Pete Posted November 26, 2013 Author Share Posted November 26, 2013 Hmmm... it seems I can instead do this instead of returning false in my code above: $this->session->redirect('../'); This way it shows the message, prevents the action and returns the user to the page tree. Only problem then is if they move it via drag and drop in the tree and it breaks the JS a bit, but at least it prevents the action. I guess my new question is: "is there a better way?" Link to comment Share on other sites More sharing options...
Pete Posted November 26, 2013 Author Share Posted November 26, 2013 Ah, but I can't change the page's status Doing this before the redirect doesn't save: $page->addStatus('Page::statusHidden'); $page->save(); Code is now as follows: public function ready() { $this->pages->addHookBefore('trash', $this, 'preservePages'); $this->pages->addHookBefore('delete', $this, 'preservePages'); } public function preservePages(HookEvent $event) { $page = $event->arguments[0]; if ($this->page->template = 'template-name') { $page->addStatus('Page::statusHidden'); $page->save();; $this->message('Page has been hidden instead of deleted - need to work on the wording'); $this->message("The page was hidden instead of deleted. Pages using the '" . $page->template . "' template can be linked to other pages, so deleting is prohibited"); $this->session->redirect('../'); } } Link to comment Share on other sites More sharing options...
Soma Posted November 26, 2013 Share Posted November 26, 2013 how about public function preservePages(HookEvent $event) { $event->replace = true; ... Thanks for the beer. Really strange that you can't just remove permission to delete pages, for what reason? Feels weird when deleting page and it just gets hidden. 1 Link to comment Share on other sites More sharing options...
Pete Posted November 26, 2013 Author Share Posted November 26, 2013 Thanks Soma, my function is now a lot shorter. I just can't get it to save the page status as hidden now though - any ideas? Basically there is a chance of someone other than me having superuser privileges and I don't want them to tweak some settings and accidentally delete a page. Just trying to make it super-foolproof. Link to comment Share on other sites More sharing options...
Soma Posted November 26, 2013 Share Posted November 26, 2013 not as a string should work... $page->addStatus(Page::statusHidden); Cheers 2 Link to comment Share on other sites More sharing options...
Pete Posted November 26, 2013 Author Share Posted November 26, 2013 Thanks again Soma, I feel like an idiot right now having the status as a string (not done it anywhere else in my modules so was just being blind ). All working now - for those interested, this is the final code: public function init() { $this->pages->addHookBefore('trash', $this, 'preservePages'); $this->pages->addHookBefore('delete', $this, 'preservePages'); } public function preservePages(HookEvent $event) { $page = $event->arguments[0]; if ($page->template == 'template-name') { $page->addStatus(Page::statusHidden); $page->save(); $event->replace = true; $this->message("The page was hidden instead of deleted. Pages using the '" . $page->template . "' template can be linked to other pages, so deleting is prohibited"); } } As you can see, much simpler after Soma's expert help. @Soma: I can't mark both your replies as the Solved post, so will have to mark this one with the full code if that's okay? 4 Link to comment Share on other sites More sharing options...
Soma Posted November 26, 2013 Share Posted November 26, 2013 Heh, I once tried for ages to use "status<Page::statusHidden" in a selector string... BTW where is the if ($this->page->template = 'template-name') { gone? Link to comment Share on other sites More sharing options...
Pete Posted November 26, 2013 Author Share Posted November 26, 2013 Heh, I once tried for ages to use "status<Page::statusHidden" in a selector string... BTW where is the if ($this->page->template = 'template-name') { gone? Fixed - just realised it as you were posting! Link to comment Share on other sites More sharing options...
Soma Posted November 26, 2013 Share Posted November 26, 2013 Just for the record and for those wondering what $event->replace = true; does: It prevents the hooked function to get executed when you use addHookBefore(). 2 Link to comment Share on other sites More sharing options...
Pete Posted November 26, 2013 Author Share Posted November 26, 2013 And for those that don't know, you can do this in ProcessWire if you want to match against multiple templates, like this: if ($page->matches('template=template1|template2|template3|template4')) { ... instead of this: if ($page->template == 'template1' || $page->template == 'template2' || $page->template == 'template3' || $page->template == 'template4') { ... Just thought that was worth sharing as I was typing it the long-hand PHP way just now and stopped myself before I wrote a lot of extra characters for no real reason! A shorter PHP alternative than above would be this: if (in_array($page->template, array('template1', 'template2', 'template3', 'template4')) { ... but I much prefer the ProcessWire version. $page->matches is a lovely thing that can be used to test the current page against any selector you can think of that makes sense in your situation. 4 Link to comment Share on other sites More sharing options...
Soma Posted November 26, 2013 Share Posted November 26, 2013 good one I also wrote about in some thread... and for those being even more lazy can also use the even shorter $page->is(selector) if($page->is('template=template1|template2|template3|template4')){ edit: or if just for one template instead if($page->template == "basic-page"){ use if($page->is("basic-page")){ 5 Link to comment Share on other sites More sharing options...
Pete Posted November 26, 2013 Author Share Posted November 26, 2013 Ah, cool. The cheatsheet says that "matches" matches the selector, whilst "is" matches template, status or selector. And for those that haven't read the Cheatsheet by now, here you go: http://cheatsheet.processwire.com/ Soma - I feel like we've just taught a class or something 2 Link to comment Share on other sites More sharing options...
Soma Posted November 26, 2013 Share Posted November 26, 2013 right $me->is("have-fun") 2 Link to comment Share on other sites More sharing options...
adrian Posted November 27, 2013 Share Posted November 27, 2013 You guys are on fire - nice work Professors Soma and Pete 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