-
Posts
1,423 -
Joined
-
Last visited
-
Days Won
18
Everything posted by Juergen
-
Another approach would be to add the CSS classes with Jquery onload, but you are also not aware of changes in the future. I use the first method for years now and I had no problems. I dont think that there will be major changes taken in the future. At the moment you could only change some attributes of the form tag, but not for the inputs.
- 5 replies
-
- 1
-
-
- styling
- comments module
-
(and 2 more)
Tagged with:
-
Take a look at this post (https://processwire.com/talk/topic/17263-custom-comments-form-and-list-styling/?do=findComment&comment=151627): You can copy the comment files from wire/modules into the module folder of your site folder (site/modules) and there you can change your CSS classes and the markup too. I think this is the best approach to adapt the comments output to your needs. You dont need to hack anything and it will not be overwritten during updates.
- 5 replies
-
- 1
-
-
- styling
- comments module
-
(and 2 more)
Tagged with:
-
Hello, I want to reset the tracked changes on the edited page if a checkbox is checked. But unfortunately the changes are still there. Here is what I have so far: $pages->addHookBefore('saveReady', function($event) { $page = $event->arguments[0]; if($page->createevents == true) { $page->resetTrackChanges(); } }); So its a simple hook that runs before the page is saved. If the checkbox called "createevents" is checked, then the tracked changes should be reset. But this doesnt work. I was looking at http://cheatsheet.processwire.com/pagearray-wirearray/change-tracking/a-resettrackchanges/ and also at this post from Ryan (https://processwire.com/talk/topic/4880-questions-about-the-usage-of-trackchanges/?do=findComment&comment=47670) but I dont know why it is not working. Only to mention: I use the latest dev and PHP 7 Maybe someone can help me out?
-
Sometimes you need to track changes in certain values of a page to take an action afterwards. In this example I will show you how to show a simple message after changes to inform the user that field values have been changed. Put this piece of code inside your ready.php. //Track changes $pages->addHookAfter('saveReady', function($event) { $page = $event->arguments[0]; if(!in_array($page->template->name, array('template1','template2'))) return; $fields = array('field1','field2','field3','field4'); $changedfieldsarray = array(); foreach($fields as $field) { if ($page->isChanged($field)) { $changedfieldsarray[] = $page->fields->get($field, true)->label; } } $fieldnames = implode(", ", $changedfieldsarray); $this->warning(sprintf(__("Following fields have been changed: %s"), $fieldnames )); }); The first restriction in this example is to run this hook "aftersaveReady" and only on certain templates: in this case template1 and template 2. You need to rename this to your template names. Remove the following line of code if you want it to run on all pages (no restrictions): if(!in_array($page->template->name, array('template1','template2'))) return; Now you have to define the fields where you want to track changes (take a look at this line): $fields = array('field1','field2','field3','field4'); In this case the fields are called "field1 to field4". Rename it to your field names. The API call to track changes is "$page->isChanged('fieldname')". You will find more information at https://processwire.com/api/ref/page/is-changed/. Use a foreach to loop through the fields array and store all changed fields inside an array. In the last step all the changed fields were outputted inside a message to inform the user. In this case I want to show the labels instead of the field names. Only to mention: The changes will keep alive, so you have to delete it manually (http://cheatsheet.processwire.com/pagearray-wirearray/change-tracking/a-resettrackchanges/). This little tutorial should only be a starting point for your own coding.
-
Hello, this is an issue I was struggeling for a while to find a working solution: The goal: A page must contain at least 1 child page. If there are more child pages than prevent the editor (user) from deleting the last child page and output a message that the deletion of the last page is not allowed. Idea behind this: I have pages which holds all the information of events, but the date or dates of the event are all located in child pages: - event page - event date 1 - eventdate 2... and so on. Each event must have at least on date. An event with no date doesnt make sense. This was the reason to not allow the deletion of the last date. Here is the code that you should copy into your ready.php $wire->addHookBefore("Pages::trash", function($event) { $page = $event->arguments(0); if(!in_array($page->template->name, array('single-date', 'single-event', 'single-business-vacation', 'single-special-business-hours'))) return; $parent = $page->parent; $childrennumber = count($page->parent->children); if($childrennumber === 1) { $event->replace = true; // now original function won't be called $event->return = $this->warning("Trashing not allowed!"); } else { $this->message("1 Page was deleted"); } }); 1) You must hook before the page will put to trash so "addHookBefore" has to be used 2) If you want to restrict it to certain types of templates than put the names of the templates in an array (in this case the templates I want to run the hook are "single-date, single-event, single-business-vacation or single-special-business-hour". If you want it to run on all pages simply remove this line from the code: if(!in_array($page->template->name, array('single-date', 'single-event', 'single-business-vacation', 'single-special-business-hours'))) return; 3) You need to get the number of all child pages from the parent to check if it is the last child or not. If there are more than 1 page and you delete on of them you get the message "1 page deleted" - so everthing is ok and the deletion of the page take place 4) If it is the last child than the trash function will be replaced by a message. So the trash function will not be executed and the warning message will be displayed instead. 5) Inform the editor with this message that the deletion of the last child is not allowed. I use here the message type "warning" (color orange), but you can also use "error" or "message" Thats all - hope this is useful for others that need something similar Only to mention: This works also via Ajax deletion fe in the page tree, but in first instance it seems that the last child was deleted because it disappears, but after refreshing the page the last child will be visible again.
-
Hook to change page status depending on children
Juergen replied to Juergen's topic in General Support
Here is the final code the prevents the deletion of the last child: I restrict it that the child is type of one of the following templates: single-date, single-event, single-business-vacation or single-special-business-hours. //Prevent deletion of the the last child $wire->addHookBefore("Pages::trash", function($event) { $page = $event->arguments(0); if(!in_array($page->template->name, array('single-date', 'single-event', 'single-business-vacation', 'single-special-business-hours'))) return; $parent = $page->parent; $childrennumber = count($page->parent->children); if($childrennumber === 1) { $event->replace = true; // now original function won't be called $event->return = $this->message("Trashing not allowed! There must be at least 1 page."); } }); I put a complete description in the Tutorial section -
Hook to change page status depending on children
Juergen replied to Juergen's topic in General Support
Ok, I have found a solution to prevent the deletion of a page: $wire->addHookBefore("Pages::trash", function($event) { $page = $event->object; $event->replace = true; // now original function won't be called $event->return = $this->message("Trashing not allowed!"); }); So it must be adapted to only run on certain templates and if there is only 1 child. -
Hook to change page status depending on children
Juergen replied to Juergen's topic in General Support
An idea would be to check the number of children before the deletion. If there is only 1 child than prevent processing of the delete function. Maybe lets say a hook that prevents the execution of the deletion???? Something like $event->replace = true; -
Hello @ all, I have the following scenario: A parent page status should be changed depending on the number of children. If there is at least 1 child the status should be published, if there are no children the statuts should be unpublished. Seems easy to realize at first sight, but ... the button of the parent page should also change. If there are children (at least 1): Only the save button should be displayed. If there are no children: The 2 buttons should be displayed. The children will be created or deleted via a Pagetable field and can be also created by clicking a checkbox in the parent page. I have tried to hook into "added" and "deleted" and also "trashed" to set the page->parent->status and it seems to work, but the button appearence will not change. So the status of the parent page seems to be changed but not the buttons (that is the problem) . Here is what it looks like after deleting of the last child: As you can see the status of the page was changed to "2048" which is unpublished, but the button is the same as before (no change). If you take a look into the settings tab you will see that the checkbox for unpublish is also not checked: The buttons change only if I hook into "before save ready" but this kind of hook doesnt take care of added or delete pages. It is also not possible to check for hasChildren because the creation of the children take place after saving of the parent page. Does someone has struggled with the same problem and has a working solution? Another approach would be to prevent the deletion of the last child.
-
Hello @ all, It want to change the markup of the notices (error, warning, message) a little bit. By default error messages in the admin look like this: There is the hint that a field is required and next to this message is the name of the field in parenthesis. This is the point, where I like to hook into. I want to replace the name of the field by the field label because editors dont know what the name of the field is. So if the user is not superuser this hook should take place. It is not a thing that is very important to me, but if there is a render function of the messages that will be hookable, it would be great if someone can tell me about. I have taken a look at https://processwire.com/api/hooks/captain-hook/ but I cannot find anything so maybe it will not be possible. But who knows....
-
I am using it too and I have not detected any problems since then.
-
Problem with field validation and values added via saveReady hook
Juergen replied to Juergen's topic in General Support
No need to investigate further. I have disabled the validation if the value will be added via a hook. The validation only take place if the value is entered manually -
Hello @ all, I cannot find a solution for this behavior: I want to validate a field which value is sometimes filled out manually and sometimes via a hook. The custom validation was done with this type of hook: $pages->addHookAfter("InputfieldDatetime::processInput", function($event) { The hook for adding a value in this field is done via this type of hook: $pages->addHookBefore('saveReady', function($event){ The 2 hooks work but the problem is that "processInput" runs before "saveReady" and so I always get the error that the field is empty. But the value will be added correctly if you can see at the following screenshot. If I fill out the value manually everything works. So which type of hook runs before "processinput" and can be used to populate a field with a value. Thanks
-
I know, this is the solution if you have only 1 template assigned.
-
How to store translateable value in multilanguage textfield via API
Juergen replied to Juergen's topic in General Support
My final solution is to use a Hook as @LostKobrakai recommended: Here is an example for others to hook into the page tree label. Code has to be placed inside ready.php $wire->addHookAfter('ProcessPageListRender::getPageLabel', function($event) { $label = $event->object; $page = $event->arguments(0); if($page->template->name == "single-date"){ $event->return = $page->title.'-test'; } }); For testing purposes I only use it on one template type called "single-date" and I change the label from "title" to "title + test". Here is what it looks like: As you can see the text "test" will be added on that template type next to the page title. This is only for others to see how it can be done. You have the idea. Only to mention: You will only need this Hook if you want to add text or values which are not stored in the DB. Otherwise you can use the field in the template settings. -
If you want to add your own button value at the add button of a pagetable field, you only have to put this little piece of code inside your ready.php file. $wire->addHookBefore('InputfieldPageTable::render', function($event) { $table = $event->object; if(!in_array($table->name, array('datespagetable'))) return; $this->addHookBefore("InputfieldButton::render", null, function(HookEvent $event){ $button = $event->object; if($button->name == 'button'){ $button->attr('value', 'Test'); } }); }); In this case I limit it to a certain pagetable field called "datespagetable". You have to change it to the name of your desired pagetable field. If you want to change it for all pagetable fields (no restrictions) simply remove the following line from the code: if(!in_array($table->name, array('datespagetable'))) return; If you want to add it to more than 1 pagetable field, then write all the fieldnames into the array: if(!in_array($table->name, array('datespagetable','pagetable1','pagetable2'))) return; You can change the value of the button text to your needs in this line of code: $button->attr('value', 'Test'); I simply called it "Test" in this case to show how it is working. If you need it to be a translateable string simply use: $button->attr('value', __('Test')); And now this is the result: This let you customize your pagetable field a little bit. Fe you can use "Add News" or "Add new events" or something else. If you want to change another attribute than the value please take a look at the following page: https://github.com/processwire/processwire/blob/master/wire/modules/Inputfield/InputfieldButton.module Best regards
-
Here are all enhancements for the template select field that I have used: 1) On page add process: Make an empty option at the top (thanks @Robin S for the easier solution) and give the user a note to select a template (optional add an additional class to style the inputfield) 2) On page edit process: Show the template select field inside the content tab instead of the settings tab (thanks @abdus), give the user a note to save the page after template change and optional add an additonal class to style the inputfield. Here are the complete code lines which should be copied into the ready.php. // 1) Template select field enhancements //a) add empty select on top of template and additional note select on page add $wire->addHookAfter('ProcessPageAdd::buildForm', function(HookEvent $event) { $form = $event->return; $template_select = $form->getChildByName('template'); $options = $template_select->getOptions(); $options = array('' => '') + $options; $template_select->set('options', $options); // Set the value to something that will never match an option in the select (any string will do) $template_select->value = 'a'; $template_select->attr('required', 1); $template_select->notes = __("Please select which type of page you want to create first."); //$template_select->addClass('importantfield', 'wrapClass'); //optional }); //b) Add class and additional note to template select field on page edit $wire->addHookBefore('InputfieldSelect::render', function(HookEvent $event) { if($this->process != 'ProcessPageEdit') return; $page = $this->process->getPage(); $inputfield = $event->object; if($inputfield->name === 'template') { $inputfield->notes = __("If you want to change the template, then choose your desired template and press the save button before filling out the fields."); //$inputfield->addClass('importantfield', 'wrapClass'); //optional } }); //c) move template select to content tab on page edit wire()->addHookAfter('ProcessPageEdit::buildForm', function ($event) { // make sure we're editing a page and not a user if ($event->process != 'ProcessPageEdit') return; $page = $event->object->getPage(); // does page template start with event_? if (strpos($page->template, 'event_') !== 0) return; $form = $event->return; $contentTab = $form->children->get('id=ProcessPageEditContent'); $settingsTab = $form->children->get('id=ProcessPageEditSettings'); if (!$settingsTab) return; $template = $settingsTab->get('template'); if (!$template) return; $settingsTab->remove('template'); $contentTab->prepend($template); }); Here are some screenshots: a) Page add As you can see the wrapper of the inputfield is grey in this case - this is because I have added a custom class to mark this field as important (background: #ddd). b) Page edit Maybe this could be useful for others too, so feel free to try it out if you want.
-
In my case I have a parent template for events. Under this parent the editor can create events and he can choose between 4 different type of events (at the moment). Each of them has its own template and form with different fields. Therefore it is necessary in this case that editors can choose between these types (depending on which type of event should be added). Fe if the editor wants to add a new event with price, max. participants, deadline for reservation and so on.. he needs other input fields than if he wants to add only a date for a company vacation. It would be great if this could be part of the core (fe with the option to select in the settings if a "Please select" should be displayed or not).
-
This is my last an best working approach with no JS (only PHP). In this case I use a Hook with a regex and a session variable to add an additional option tag with "Please select" at the top. So the user has to select one of the template types. Otherwise he will get an error message. Only to mention: There is also another Hook used to create the notice at the bottom (but this is not part of this topic ) Here is the code, which should be placed inside ready.php: $wire->addHookAfter('InputfieldSelect::render', function(HookEvent $event) { if($this->process != 'ProcessPageAdd') return; $inputfield = $event->object; if($inputfield->name === 'template') { $regex = '#<\s*?select\b[^>]*>(.*?)</select\b[^>]*>#s';//regex to get all content (options) between the select tags $str = $event->return; preg_match($regex, $str, $match); $origoptions = $match[1];//get all original options $options = $origoptions; if(isset($_POST['template'])) wire('session')->selectedoption = wire('input')->post('template');//set session after POST if(wire('session')->selectedoption){ wire('session')->remove('selectedoption');//remove session } else { $options = str_replace("selected='selected'", '', $origoptions); //remove selected attribute on first load } $newoptions = '<option value="">'.__("Please select").'</option>'.$options;//create all options including the empty option tag at the beginning $result = str_replace($origoptions, $newoptions, $str);//replace the original options with the new options $event->return = $result; } }); Short explanation: The regex is used to get all options between the select tags (needed a little bit later to add the additional option tag on the top) The session is used to check if the page is loaded for the first time. If yes (no session created) than the pre-selected option will be removed, so that the "Please select" option will be selected on the first page load. The session will be removed afterwards. So this step is only necessary to get the "Please select" as pre-selected value on the first page load. Afterwards the additional option tag with "Please select" will be added to the original option tag which was grabbed with the regex. The final step is to output the modified select. At the moment I didnt find any problems or errors with this code, but if someone has some improvements please let me know. Best regards
-
Thank you @Robin S, your solution works!!! Also thank you for your detailed explanation, but where do you get all your knowledge about Hooks ? A big thanks to all other contributors for your help!
-
Thank you @kixe I will try this tomorrow.
-
I have put the code inside the ready.php, but I need to run it only on certain templates and under certain conditions. Therefore I need the page to get the template associated with it. So I dont want to disable them permanently only if the page has no children. If childrens were created the field should be enabled. The idea is to make this field (a checkbox field) checked and disabled if there are no children created. If the user has created at least 1 child page, then this checkbox field will be unchecked and enabled. The automatic checking works with this Hook after a new page (with no children) is added //Set create events to true if there are no child pages $this->pages->addHookAfter('added', function($event) { $page = $event->arguments('page'); $field = $event->arguments('field'); if(in_array($page->template->name, array('event_businessvacations','event_specialbusinesshours','event_dates','event_events'))) { if(count($page->children) == 0){ $page->setAndSave('createevents', true); } } }); To prevent the user to uncheck the checkbox I want to disable it in this case.