Jump to content

Search the Community

Showing results for tags 'hooks'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


  • Welcome to ProcessWire
    • News & Announcements
    • Showcase
    • Wishlist & Roadmap
  • Community Support
    • Getting Started
    • Tutorials
    • FAQs
    • General Support
    • API & Templates
    • Modules/Plugins
    • Themes and Profiles
    • Multi-Language Support
    • Security
    • Jobs
  • Off Topic
    • Pub
    • Dev Talk

Product Groups

  • Form Builder
  • ProFields
  • ProCache
  • ProMailer
  • Login Register Pro
  • ProDrafts
  • ListerPro
  • ProDevTools
  • Likes
  • Custom Development

Find results in...

Find results that contain...

Date Created

  • Start


Last Updated

  • Start


Filter by number of...


  • Start





Website URL







  1. I took Ryan's old Page Edit Per User module and modified it to: Allow users to assign access on pages they have edit access on (and pages they create) Check a field on the page, and current user, and make sure there is a matching value (ex: multiselect field on both the user account and the page) Allow adding pages so long as they have access to a parent page Setup: Assign a role that has "page-edit" granted, but no templates are explicitly assigned to this access. A multiselect text tag field is assigned to both the user profile template, and any templates of pages that I want the ability for access levels to be controlled. (example values of tags: HR, PR, IT, Administration, ...etc...) When a user has a tag value assigned that matches a page's tag value, access to edit (and/or add) is granted. It's mostly working (from the page tree) (I thought it was, the add button is visible, but the same error is displayed when clicking it); I have one instance where a parent isn't displaying the add button for children, but I'll look at that shortly... What definitely is not working: the "Add New" button is (surprisingly) properly displaying templates of pages that users have access to add based on my changes, but once a user tries to use that button, it displays the following error: This makes sense since the role doesn't assign any explicit templates, but now I'm trying to override that. I suspect once I fix this that there will be another area I'll also need to hook, but... This message is part of ProcessPageAdd::___execute(). I tried to hook into `ProcessPageAdd::getAllowedTemplates` because in `execute`, it throws that error only if the template of the page to add isn't already defined in ProcessPageAdd::allowedTemplates. I might be going about this all wrong, but in the init() method of my adjusted PageEditPerUser, I have the following: wire()->addHookBefore('ProcessPageAdd::getAllowedTemplates', $this, 'hookAllowedTemplates'); ...and then the method: /** * ProcessPageAdd::getAllowedTemplates hook * */ public function hookAllowedTemplates($event) { // bd('hookAllowedTemplates'); // bd($event, 'event'); // bd($event->object, 'event->object'); // bd($event->arguments(), 'event->arguments'); $event->replace = true; $allowedTemplates = []; $allowedTemplates[input()->get->template_id] = templates()->get(input()->get->template_id); return $allowedTemplates; } One thing I struggle with, without others' examples, is what return value (and format) is expected from pre/post hooks. In this case I tried to completely replace the call to ProcessPageAdd::getAllowedTemplates because the value of $event->object->allowedTemplates in the post-hook is similar to a numerically indexed (by template ID) array of a template object (but contains a few more properties), but I still received the error as shown above. (I know I'll need to do more checks on the values assigned in the above method call depending on scenario; right now my tests all have valid parent and template IDs, so I just want to get that working first.) Any potential thoughts, either at what to look at, or where to further debug? (...or more code to share?)
  2. I am using FormBuilder to collect data and save it to pages. The forms (and the page templates used) use file fields to collect PDF files. The uploaded files should automatically be renamed to match the name of the fields. This should happen every time a page is saved. The first time after the form is saved to the page, but also on every other page save, because editors could have added or exchanged some of the files and then they should be renamed again. I tried to solve this in different ways, but nothing really worked as expected. What I tried: $this->wire->addHookBefore("Pages::saveReady(template^=application_entry)", function(HookEvent $event) { $page = $event->arguments(0); // get all fields of fieldtype file $fileFields = $page->fields->find('type=FieldtypeFile'); // loop through all file fields foreach($fileFields as $field){ $fieldname = $field->name; $field = $page->get($field->name); $index = 1; foreach($field as $item){ $newFilename = $fieldname; // if there are multiple files, add index to filename if(count($field) > 1){ $newFilename .= "-".$index; $index++; } $newFilename .= '.'.$item->ext; // bd($item->basename()." -> ".$newFilename); // only rename if filename is not already set if($item->basename() != $newFilename){ $item->rename($newFilename); } } } $event->arguments(0, $page); }); When I save an existing page, the files are renamed, but I get the following error message and the filename change is not reflected in the database: If the page has not existed before save (got created by FormBuilder) I get a message that it was created, but it does not get created and FormBuilder shows a Not yet created in the entries list. Another approach was this: $this->wire->addHookAfter("Pages::saved(template^=application_entry)", function(HookEvent $event) { $page = $event->arguments(0); // get all fields of fieldtype file $fileFields = $page->fields->find('type=FieldtypeFile'); $page->of(false); // loop through all file fields foreach($fileFields as $field){ $fieldname = $field->name; $field = $page->get($field->name); $index = 1; foreach($field as $item){ $newFilename = $fieldname; // if there are multiple files, add index to filename if(count($field) > 1){ $newFilename .= "-".$index; $index++; } $newFilename .= '.'.$item->ext; bd($item->basename()." -> ".$newFilename); // only rename if filename is not already set if($item->basename() != $newFilename){ $item->rename($newFilename); $page->save(); } } } }); This also renames the file on save, but the filename in the field is still the old name. I am using pagefileSecure on this template (if that matters). Any help his highly appreciated! Thanks in advance, Flo
  3. I would like to run this via a hook: $page->of(false); foreach($page->table as $row) { if($row->pass == "") { $pass = new Password(); $string = $pass->randomAlnum(22); $row->pass = $string; } } $page->save('table'); and tried this: $this->addHookAfter('Pages::save', function($event) { $p = $event->arguments('page'); if($p->id == 1599) return; // my page $p->of(false); foreach($p->table as $row) { if($row->pass == "") { $pass = new Password(); $string = $pass->randomAlnum(22); $row->pass = $string; } } $p->save('table'); }); But I get a 500 error. Is it an infinite loop? SOLVED
  4. I need to show (in my backend) since when a page special type of page has been published (not created, as there may be a long delay between creation and publishing). So I made a datefield in my template and added following code to my site\ready.php $wire->addHookBefore('Page(template=templateName)::published', function($event){ $page = $event->arguments(0); $this->message("the Hook has been called"); if($page->hasField("myDateField")) { $newDate = date("d.m.Y"); $page->myDateField = $newDate; } }); But for some reason the hook is not called when I publish the page. Is there something I'm missing?
  5. Preventing a page from being moved is not necessarily a straightforward matter of trapping the change in a save hook in the same way as a page edit. A problem occurs if the page is only to be 'blocked' conditionally - when the page path is in some given array, for example. In hooking before page save, the page path is the new page path after the move, rather than before it, so you need to do something like this: // .... In the before page:saveReady hook // $page is the page :) The code below operates when (isset($page->parentPrevious) && $object->parentPrevious != $object->parent) $name = $page->parentPrevious->path . $page->name . '/'; // need the path before it was moved if(in_array($name, $blockedNames)) { // $blockedNames are the ones where we don't want moves // Because this hook operates after the move, we need to reverse the move $page->parent = $page->parentPrevious; // Alternatively, to completely stop the save //$event->replace = true; //$event->return = false; } //... rest of hook This prevents the page being moved, both in the page hierarchy (by dragging) or in the page editor by changing the parent in the settings tab. It is also possible to hook before Page:moveable with something like this /** @var Page $page */ $page = $event->object; $moveable = $event->return; // ... code to set $moveable to false if conditions met $event->return = $moveable; Interestingly, the (not documented?) moveable method is created as a hook by PagePermissions and so is hookable. However, this method appears to catch only the situation where the move is effected by dragging the page in the tree, not when the parent is changed in the settings.
  6. $wire->addHookAfter('Pages::added(template=booking)', function(HookEvent $event) { $page = $event->arguments(0); $selectable_pages = $page->getInputfield('booking_group')->getSelectablePages($page); $current_group = $selectable_pages->find("template=booking_price, parent.booking_current_group=1"); $first = $current_group->eq(0); $second = $current_group->eq(1); if ($page->booking_numberofpeople->id == 1 ) { $page->setAndSave('booking_group', $first); } else if ($page->booking_numberofpeople->id !== 1 ) { $page->setAndSave('booking_group', $second); } }); I have this code in ready.php It works when i change to (Pages::save) but when (Pages::added) it doesn´t work? It sets the value to $second regardless.. Any clues? booking_group = page reference field booking_numberofpeople = select option field the options in booking_numberofpeople is 1=1 2=2 3=3 4=4 5=5 Also i have set the required value to 1. The pages are created from the module (Simple Contact Form). Please help!!
  7. I'm trying to do something I thought would be simple, but maybe not!... I'm trying to hook ProcessPageEdit to change the label/text displayed on the page save button in certain circumstances based on fields in that page. But can't figure if it's possible to target the button. I can get to the button actions in the drop down with ProcessPageEdit::getSubmitActions but this array doesn't contain the top level label only the drop down values. Can anyone point me in the right direction here please? TIA ?
  8. I have a couple of pages that has a specific template. In the template i have a page reference field (Activator). What im trying to achive is when i select an option in the dropdown (Activator) in admin and save, then the specific option is disabled (greyed out) in all of the other pages that has the page reference field (Activator). So basically you can only select one specific option once. But when i unselect the same one i want it to be reset and can be selected again in other pages. Please help!
  9. Hey all, I have pages that can be created two ways, in the PW admin and via an endpoint where JSON data is sent. I have a hook that checks field data on page save and errors if it is not correct. I would like this to create an error in the PW admin using $this->errors, but if the page is created via the Page API in the script that handles JSON requests I want to throw an exception I can catch and handle accordingly for the JSON response. This also allows for setting a user friendly error message for the PW admin, and machine friendly data for API use. Trying to figure out how to detect which context that the page is being created in. A script, or in the PW admin and act accordingly. Is this possible?
  10. Hey all, I've been building a new feature on our PW site and the URL hooks are exactly what the doctor ordered. I am developing a RESTful web API to allow external platforms to integrate with our site. The API endpoints are namespaced at /api/v1. I am having trouble making use of the named route parameter using regex. I have a hook for /api/v1/offline-events that gets all Offline Event pages. The next route to be defined is /api/v1/offline-events/{event ID}. The event ID is using a custom string (not the Page ID) that is a 15 character alphanumeric string like this: E4LxQRXZadgjstw. However when I use a PCRE compliant regular expression (tested on regexr.com) I get an error. Here is my hook code for reference and the error produced: <?php namespace ProcessWire; $wire->addHook('/api/v1/offline-events/{eventId:#(?=.{15}$)([A-Za-z0-9])\w+#}/?', function($e) { // ommitted for brevity }); // Error thrown: Warning: preg_match(): Unknown modifier '(' in /wire/core/WireHooks.php on line 1170 I've tried using all delimiters in the documentation (!@#%) but no change in the outcome. The second question is how do I create a wildcard capture for all 404s that occur after the /api endpoint? Currently it is loading the website 404 page. Many thanks!
  11. While this is working perfectly: public function init() { $this->addHookAfter('Page::render', $this, 'replaceEverything'); } This is not, nothing happens: public function init() { $this->addHookBefore('Page::render', $this, 'replaceEverything'); } replaceEverything looks simply like this: public function replaceEverything($event) { $event->return = "REPLACED, YO!"; } I want to replace the rendering entirely, so a hook after would not be efficient, since I don't need the previous rendering. What's wrong?
  12. Hi I'm working with PW for some time now, but – please don't laugh – never used hooks. I have 200 – 300 subpages with the template 'artist', the title of each page represents the full name, sometimes John Doe, sometimes John Emmet Brown Doe. I want to auto-populate the field 'artist_last_name' with the word that is most likely the last name, the last word of the page title. If there are more names, it can be changed manually. I need this for easier and quicker alphabetical sorting. What I put together is this, in ready.php. Doesn't work. Again, I'm new to hooks.. <?php $wire->addHookBefore('Pages::saved', function(HookEvent $event) { $p = $event->arguments('page'); if($p->template != 'artist') return; if($p->artist_last_name) return; $ln = end(explode(' ', $p->title)); $p->set('artist_last_name',$ln); }); ?> In the best case this would be done once globally without having to open and save every page. But new pages should populate the field on page save. Thanks for your help, I think it's easy, I just need a push.. Nuél
  13. Hi, is there a hook after the current (active) page got created? Or which method got called in the Page class after the Constructor of the current page got initialized? Thanks.
  14. I need to restrict editing access based on both the user role, and the value of a sub-field in a page reference field. eg $page->competition->closingDate There's some discussion about restricting editing access based on role, and that works, but when I try to access the page via the method @Robin S suggests, the page returned is an admin page rather than the page being edited, so I don't have access to the edited page's fields.
  15. So I thought of hooking up with hooks. I installed that "hello world" module, and now, when I save a page, I see "Hello world..." message on top -- which makes sense. To play with it further, I copied the hook code from the module to my header.php file. The code is: $pages->addHookAfter('save', $this, 'example1'); function example1($event) { $page = $event->arguments[0]; $this->message("Hello World 2 ! You saved {$page->path}."); } It is a verbatim copy of the code from the module, and it is placed in a file that gets called first via prependTemplateFile in config.php. However, now when I save a page, I don't see the message from my hook function. What could I be missing? thanks,
  16. so i am trying to put CustomHooksForVariations.module, a custom module, i am placing it into site/modules direcotry yet my modules page in admin panel gives me errors so this is the screen show when i refresh modules, i dont know why the shole hook is written on top of the page :|| and this next image is when i try to install it, i saw that it is not defiuned modules.php but it shouldnt need to be ?, any ways i dont want to edit site's core just to make one moulde work there has to be a way
  17. Am I right in thinking that multiple hooks that are added for the same event can be prioritised by doing something like this... $session->addHookAfter( 'login', $this, 'myLoginHook', array('priority'=>xyz) ); Where xyz is the relative priority for the hook and the lower the value, the earlier it will be called as the hooks are executed?
  18. Continuing my journey into PW hooks, I'm trying to find a way to retrieve all images from a page that explicitly *do not* have a certain tag (or tags) attached to them. Found this post from 2015 But I'm wondering if there's a more elegant way to go about this. Let's say I have a multi-image field called "images_header" and instead of $page->images_header->findTag('mytag'); I would like to do this: $page->images_header->excludeTag('mytag'); So I'd be able to do // find images that don't have the tag "mytag" $images = $page->images_header->excludeTag('mytag'); // check if there's any images if (count($images)>0) { // do something.. } Would this be possible by hooking into Pagefiles somehow? There's this bit in /wire/core/Pagefiles.php Line 626 that I'd basically just need to reverse (or at least in my mind ? ) public function findTag($tag) { $items = $this->makeNew(); foreach($this as $pagefile) { if($pagefile->hasTag($tag)) $items->add($pagefile); } return $items; } Any ideas on how this could be done in a graceful manner? Thanks in advance!
  19. Getting a little deeper into the ProcessWire state-of-mind here. I seriously think I wouldn't have come back to webdev if it wasn't for this wonderful little gem of a CMS. I have an "Options" field added to all users on a site. If the user has anything other then "default" selected, I would like to show a permanent message in the admin like the one in the screenshot, only so that the user can't close it. As a friendly reminder that he changed that option from default to something crazy ? I've read up on how to send messages to users, but where would I hook into to make this show up all the time in the backend? https://processwire.com/api/ref/wire/message/ Thanks in advance!
  20. Hello, Here's what I'm trying to achieve : I have a textarea field that is frontend editable on any page I want to. If a user with a specific role updates it, I want to tick a checkbox field on the parent page where the textarea resides. So I tried to hook as follows in my ready.php file : $this->addHookBefore('Fieldtype::savePageField', function(HookEvent $event) { $page = $event->argument[0]; $field = $event->argument[1]; if($this->user->hasRole('teacher')) { $page->alertBox = 1; } // DEBUG HERE (bd($page), l($field)... ???? }); Of course (!) it doesn't work (yet !) but the thing is I have no idea how to debug this since my bd() never triggers. I've tried the 'Event interceptor' of Tracy debugger which helped me setting up my hook. I guess my $page and $field are correct... but how could I go any further ? The road is long to become a dev (when you're not one ? )... For further information in case someone wonders : I'd like to set up a textarea that is modified by a user (having a 'player' role, ie 'student'). When front-end modified, I wish it would automatically alert me (the teacher) by ticking a box. So when I log in with my teacher role, I get a list of all textareas I have to read over. When I read/correct/update them (front-end), I would like my hook to automatically untick the box to remove it from my list. In other words, the 'textarea' status should go back and forth according to who modified it last. For the time being, I have managed to make it work with a checkbox that the user has to manually tick/untick, but I've noticed many kids forget to tick the box so they edit their text and I don't get a notice ? Thanks if anyone takes time to try and help me on that one !
  21. Hello, I'm struggling with hooks to try and do this : adding user page to a page field when visiting a particular page on my website. In fact, I want to have a list of connected users on a particular page (called meeting-hall). I've tried all kinds of things (which I don't really understand, sorry) but the latest is this : $wire->addHookBefore('Page::render', function($e) { $page = $e->arguments(0); if ($page->is("name=meeting-hall")) { $page->connected->add($user); // connected is a Page field $page->save(); } else { $meeting = wire("pages")->get("name=meeting-hall"); $meeting->connected->remove($user); $meeting->save(); } }); I put this in my _init.php file but nothing works... The best I managed was updating my 'connected' field when the user loads the 'meeting hall' page by having this on the page template : if ($user->isLoggedin()) { $page->connected->add($user); $page->of(false); $page->save(); $page->of(true); } But I wanted to remove the user when he or she leaves the page... hence my thought about using hooks... If you can give me a hint, I'd greatly appreciate !
  22. Hi guys (didn't see any gals here), I have a module which has some custom helper classes. One of these classes has methods which are hookable. The class is derived from WireData. An additional complication is that this class has its own namespace. What would be the correct way to provide the hookable methods via API? Here is a very simplified code sample of the class: <?php namespace SnipWire\Services; use ProcessWire\WireData; use ProcessWire\WireException; class Webhooks extends WireData { ... public function ___handleOrderCompleted() { if ($this->debug) $this->wire('log')->save( self::snipWireWebhooksLogName, '[DEBUG] Webhooks request: handleOrderCompleted' ); $this->responseStatus = 202; // Accepted } public function ___handleOrderStatusChanged() { if ($this->debug) $this->wire('log')->save( self::snipWireWebhooksLogName, '[DEBUG] Webhooks request: handleOrderStatusChanged' ); $this->responseStatus = 202; // Accepted } ... } The class itself is invoked/used by a hook from within the main module: Depending of the event, one of the methods of the Webhooks class above is triggered. A developer should now be able to use one of the ___handle* methods to do further things. /** * Check for webohook request and process them. * (Method triggered before ProcessPageView::execute) * */ public function checkWebhookRequest(HookEvent $event) { if ($webhooksEndpoint = $this->get('webhooks_endpoint')) { if ($this->sanitizer->url($this->input->url) == $webhooksEndpoint) { /** @var Webhooks $webhooks Custom ProcessWire API variable */ $this->wire('webhooks', new Webhooks()); $this->wire('webhooks')->process(); $event->replace = true; // @note: Tracy Debug won't work from here on as normal page rendering is omitted! } } } Should I provide a custom API variable e.g. $webhooks? Or how is the best way to do this?
  23. Hi there, I'd like to prevent duplicate values in a specific page field (FieldtypeText) across all pages. The hook should also prevent saving of the page if a duplicate value is detected. Therefore I created two hook methods but I can't get it to work properly. Here are both hooks placed in init() method of an autoloader module: The first hook is to initially preset the field with the page id. The field value can be customized by the admin before saving. The second hook should check if the value is unique. If I create a new page and try to save, the WireException is already triggered in first step of page creation, where you enter the page title: SKU [] is already in use If I check the value of $sku (with Tracy) it's always empty! Any idea what could be wrong? EDIT: if I remove the second hook, the field value is correctly preset with the page id! $this->addHookAfter('Pages::added', $this, 'presetProductFields', ['priority' => 99]); $this->addHookAfter('Pages::saveReady', $this, 'checkSKUUnique', ['priority' => 101]); And this are the hook methods: public function presetProductFields(HookEvent $event) { $snipwire = $this->wire('snipwire'); if (!$snipwire) return; $page = $event->arguments(0); if ($snipwire->isProductTemplate($page->template)) { if ($page->hasfield('snipcart_item_id')) $page->setAndSave('snipcart_item_id', $page->id); } } /** * Check if the SKU value is unique across all product pages. * (Method triggered after Pages saveReady -> just before page is saved) * * @throws WireException * */ public function checkSKUUnique(HookEvent $event) { $snipwire = $this->wire('snipwire'); if (!$snipwire) return; $page = $event->arguments(0); if ($snipwire->isProductTemplate($page->template)) { $field = $page->getField('snipcart_item_id'); $sku = $page->snipcart_item_id; // SKU field value bd($sku); if ($page->isChanged('snipcart_item_id')) { $exists = $this->wire('pages')->get("snipcart_item_id=$sku"); if ($exists->id) { // value is not unique! $error = $this->_('SKU must be unique'); $exception = sprintf( $this->_('SKU [%s] is already in use'), $sku ); $inputfield = $page->getInputfield($field); $inputfield->error($error); throw new WireException($exception); // Prevent saving of non-unique value! } } } }
  24. Hello there, and thanks for ProcessWire! I'm getting to know ProcessWire while doing my first project using it and I really like it so far. The challenge I'm facing right now is the following: I have a One-Pager using fullpage.js, realized as a single PW-Page containing a Repeater Field where each Repeater Item is one Section. Some Sections are supposed to have a little menu at the Top which references/links to different Sections of the Website, so I wanted to use a Checkbox Field "Top Menu" to decide if a Section gets a Menu and a Page Reference Field to choose the different Sections (Repeater Items) it should contain. I've already accomplished this by pasting the following code into /site/ready.php: $wire->addHookAfter('InputfieldPage::getSelectablePages', function($event) { if($event->object->hasField == 'top_menu_entries') { $page = $event->arguments('page'); if($page instanceof RepeaterPage) $page = $page->getForPage(); $event->return = $page->; } }); The only problem that still remains is that when I select the Entry of the Repeater Item itself it doesnt save the selection, meaning after I saved it's unselected again. On some Sections I do want a Menu-Entry for the Section itself though (which would be styled differently and not link anywhere) for Continuity-Reasons, any ideas on how to achieve that?
  25. Hi, can you guys help a beginner with a problem.. On my template (profile_page) i have a dropdown (page reference) where i can choose a sports team (team_page) that is related to that profile which is also its parent. Then on my Competition1 page (competition_page) I have page reference field (profiles) a dropdown that i want to display only profiles that has choose a specific sports team (template=team_page) the page parent to be specific. Structure/Template Sports_team1 (team_page) Profile1 (profile_page) Profile2 (profile_page) Profile3 (profile_page) Competition1 (competition_page) ready.php <?php $wire->addHookAfter('InputfieldPage::getSelectablePages', function($event) { if($event->object->hasField == 'profiles') { $relative = $page->parent->name; $event->return = $event->pages->find("template=profile_page, sports_team=$relative"); } }); ?> This returns with no results in the dropdown. If i remove sports_team=$relative then it displays all profiles that have profile_page as template, so it works almost. But i will have more sports teams so this is just an example. I only want to display the profiles that has choosen the parent team on there profile page in admin not front end. I hope i was able to explain it so you guys can understand a little bit. Need some help please! /Thanks
  • Create New...