FlorianA Posted August 27, 2019 Share Posted August 27, 2019 Hi, I would like to extend the (backend) edit form for some pages: Above the "Save" button there should be an additional checkbox "Notify users about changes". If this checkbox is checked, an e-mail notification about the page's changes should be sent to other users. My plans for implementation are the following: Anyhow add a hook on rendering the form and insert a checkbox at the appropriate place. Hook the saving of the form, check the state of the checkbox and send the e-mail, if wanted. However, I'm struggling with the details. Which method should be hooked for step 1? InputFieldForm::render? How can I get the current form data? How can I extend it? Is there already a module which does all this stuff for me? (Not really sending the e-mail but all the hooking stuff, that's a pattern I would like to reuse form something else later.) Thanks in advance for any help. Link to comment Share on other sites More sharing options...
elabx Posted August 27, 2019 Share Posted August 27, 2019 36 minutes ago, FlorianA said: Anyhow add a hook on rendering the form and insert a checkbox at the appropriate place. Hook the saving of the form, check the state of the checkbox and send the e-mail, if wanted. My normal take on this is adding a normal checkbox field to the template (even though I guess it's an overkill ). That way on Pages::saved I can check for the value and reset it to unchecked saving only the field. Probably adding the field through an "after" hook on ProcessPageEdit::buildForm (or buildFormContent) as it returns the object that has the form fields so you can go through them and add other stuff you might need. Though I wouldn't know on which other hook I could catch it to process the input. (for example, I don't know if the data from this fake field would reach Pages::saved or even create an error). 1 Link to comment Share on other sites More sharing options...
Robin S Posted August 27, 2019 Share Posted August 27, 2019 A couple of hooks for /site/ready.php: $wire->addHookAfter('ProcessPageEdit::buildFormContent', function(HookEvent $event) { /* @var InputfieldWrapper $form */ $form = $event->return; // Maybe return early if page does not use a particular template /* @var ProcessPageEdit $ppe */ $ppe = $event->object; /* @var Page $page */ $page = $ppe->getPage(); if($page->template != 'basic_page') return; // Add checkbox field /* @var InputfieldCheckbox $f */ $f = $event->wire('modules')->InputfieldCheckbox; $f->name = 'notify'; $f->label = 'Notify users about changes'; $form->add($f); }); $wire->addHookAfter('ProcessPageEdit::processInput', function(HookEvent $event) { /* @var InputfieldWrapper $form */ $form = $event->arguments(0); // We only care about the top-level form $level = $event->arguments(1); if($level) return; // Get the notify field $notify = $form->getChildByName('notify'); // Return early if notify field doesn't exist or isn't checked if(!$notify || !$notify->value) return; // Now send the email notification... // Your code here }); 4 Link to comment Share on other sites More sharing options...
elabx Posted August 28, 2019 Share Posted August 28, 2019 Thanks @Robin S ! I won't add useless Checkboxes anymore to my templates! :D 1 Link to comment Share on other sites More sharing options...
bernhard Posted August 28, 2019 Share Posted August 28, 2019 9 hours ago, Robin S said: // We only care about the top-level form $level = $event->arguments(1); if($level) return; Hey @Robin S could you please explain this part. I know I've seen this $level check somewhere in the core but I've never come to a situation where I needed it for myself (and I've hooked processInput often, so maybe I'm missing something?). Thx Link to comment Share on other sites More sharing options...
Robin S Posted August 28, 2019 Share Posted August 28, 2019 1 hour ago, bernhard said: Hey @Robin S could you please explain this part. ProcessPageEdit::processInput() calls itself recursively for every instance of an InputfieldWrapper found within the form, incrementing $level for each nesting. But because we know we have added the notify checkbox field at the top level there's no point in looking for it within any nested InputfieldWrapper. Link to comment Share on other sites More sharing options...
bernhard Posted August 28, 2019 Share Posted August 28, 2019 3 hours ago, Robin S said: ProcessPageEdit::processInput() calls itself recursively for every instance of an InputfieldWrapper found within the form, incrementing $level for each nesting. But because we know we have added the notify checkbox field at the top level there's no point in looking for it within any nested InputfieldWrapper. Ok that's what I was guessing. And I understand why it has never been an issue for me: $wire->addHookAfter('ProcessPageEdit::processInput', function(HookEvent $event) { /* @var InputfieldWrapper $form */ $form = $event->arguments(0); if($form->name != 'myform') return; ... }); I'm usually checking for the name, so $level is not issue ? Link to comment Share on other sites More sharing options...
FlorianA Posted August 28, 2019 Author Share Posted August 28, 2019 Thanks @Robin S for this really nice piece of code. Works out of the box ? One more question: When exactly the ProcessPageEdit::processInput hook is being triggered? I want to be sure that users are notified only after page data really has been saved. Link to comment Share on other sites More sharing options...
Robin S Posted August 28, 2019 Share Posted August 28, 2019 3 hours ago, FlorianA said: When exactly the ProcessPageEdit::processInput hook is being triggered? As the name would suggest, it's triggered when the input values in the Page Edit form are processed. ? 3 hours ago, FlorianA said: I want to be sure that users are notified only after page data really has been saved. There aren't really any circumstances when page data will not be saved when the Page Edit form is submitted, apart from a fatal PHP error due to some mistake in your code. The situations where a page save might be attempted but not actually occur are outlined in this code, but these are only likely to happen when a page is being saved via the API. Are you thinking of warnings caused by empty required fields? Because page data is still saved in that case. But if you don't want an email to be sent if there are empty required fields you can check to see if there are any form errors: // Return early if there are any form errors if(count($form->getErrors()) return; 1 Link to comment Share on other sites More sharing options...
bernhard Posted August 29, 2019 Share Posted August 29, 2019 Taking Robins example I'd also add some feedback for the user: $wire->addHookAfter('ProcessPageEdit::processInput', function(HookEvent $event) { /* @var InputfieldWrapper $form */ $form = $event->arguments(0); // We only care about the top-level form $level = $event->arguments(1); if($level) return; // Get the notify field $notify = $form->getChildByName('notify'); // Return early if notify field doesn't exist or isn't checked if(!$notify || !$notify->value) return; // Now send the email notification... if($form->getErrors()) { $this->error('Mail NOT sent'); return; } else { $mail = new WireMail(); $mail->to(...)->from(...)->... $sent = $mail->send(); if($sent) $this->message('Mail was sent successfully to ...'); else $this->error('Error sending mail to ...'); } }); Link to comment Share on other sites More sharing options...
FlorianA Posted August 30, 2019 Author Share Posted August 30, 2019 I'm just considering, if I should rather hook Pages::saved than ProcessPageEdit::processInput. The advantage is that I can get information about which fields have changed. So I can send the e-mail notification only if some important fields have changed. It seems that I can still access the "notify" value of my checkbox - it is contained by the "changes" parameter exactly if it differs from the default. 1 Link to comment Share on other sites More sharing options...
bernhard Posted August 30, 2019 Share Posted August 30, 2019 Sounds good ? PS: I recommend using conditional hooks as they make it very obvious what's going on when: $wire->addHookAfter('Pages::saved(template=xyz)', function ... ); PPS: I think even this should work: $wire->addHookAfter('Pages::saved(template=xyz,notify=1)', function($event) { $page = $event->arguments(0); // send email // reset checkbox $page->setAndSave('notify', 0); }); Link to comment Share on other sites More sharing options...
FlorianA Posted September 4, 2019 Author Share Posted September 4, 2019 On 8/30/2019 at 6:05 PM, bernhard said: PPS: I think even this should work: $wire->addHookAfter('Pages::saved(template=xyz,notify=1)', function($event) { $page = $event->arguments(0); // send email // reset checkbox $page->setAndSave('notify', 0); }); Yes, it works indeed ? But I wonder if it's really necessary to reset the 'notify' flag, as it does not belong to the page template but has just been injected into the form by the buildFormContent hook above. I'm lucky enough still finding the field in the Pages::saved hook, but it isn't saved with the page, is it? 1 Link to comment Share on other sites More sharing options...
bernhard Posted September 5, 2019 Share Posted September 5, 2019 10 hours ago, FlorianA said: But I wonder if it's really necessary to reset the 'notify' flag, as it does not belong to the page template but has just been injected into the form by the buildFormContent hook above. I'm lucky enough still finding the field in the Pages::saved hook, but it isn't saved with the page, is it? Of course, you're right ? Forget about that! And for situations like this it's really nice to add the inputfield via hook so that no field (and table) is created unnecessarily in the database. 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