-
Posts
4,927 -
Joined
-
Days Won
321
Robin S last won the day on November 13
Robin S had the most liked content!
Profile Information
-
Gender
Male
-
Location
New Zealand
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
Robin S's Achievements
-
Robin S started following Problem with Page Autocomplete using findReady hook not saving data , New post – Implementing and using TinyMCE 6 in ProcessWire , Admin Actions and 5 others
-
New post – Implementing and using TinyMCE 6 in ProcessWire
Robin S replied to ryan's topic in News & Announcements
@ryan, is there an update on this? It would be good to have PW use the current version of TinyMCE because v6 is now past the official End Of Life. -
@adrian, wonderful, thanks!
-
Hi @adrian, Is it possible for an action to return markup apart from the successMessage and failureMessage? I'd like to use MarkupAdminDataTable to show a table of results of the action. Putting the markup in successMessage sort of works, except it has the green background so I figure it's intended for a simple sentence rather than longer markup like this. If the module doesn't already have a solution for this that I've missed, what do you think about adding a new method similar to successMessage(), or maybe if the return value of executeAction() is a string rather than boolean the module could render that under the success/failure message? Thanks for considering.
-
To do this I think you'll have to hook the rendering of the repeater item, which is a fieldset: $wire->addHookBefore('InputfieldFieldset(name^=repeater_item)::render', function(HookEvent $event) { $inputfield = $event->object; $inputfield->label = $event->wire()->sanitizer->unentities($inputfield->label); });
-
@mel47, I didn't follow everything in your post, but Dynamic Options doesn't rename your images or create any variations. Looking at your code, you want to avoid doing this: Because $par is a Pageimages object and every Pageimages object is bound to a particular page (Page A), so when you add images to it from a different page (Page B) then the image files will be copied from from Page B's folder in /site/assets/files/ to Page A's folder, and I doubt that's what you intend. I suggest you rewrite your code so that you only add the image information to the $options array. Something like: $wire->addHookAfter('FieldtypeDynamicOptions::getSelectableOptions', function(HookEvent $event) { $page = $event->arguments(0); $field = $event->arguments(1); $pages = $event->wire()->pages; if($field->name === 'image_selection') { $options = []; foreach($pages(1065)->images as $image) { $options[$image->url] = "{$image->basename}<br>{$image->filesizeStr}"; } foreach($pages(1042)->content_blocks->find("repeater_matrix_type=2") as $p) { $image = $p->images->last(); if(!$image) continue; $options[$image->url] = "{$image->basename}<br>{$image->filesizeStr}"; } $event->return = $options; } });
-
@Macrura, yeah, that's not wanted so in v0.3.6 I've excluded the inputfield mods when the process is ProcessPageListerPro.
-
TinyMCE itself supports this via the style_formats setting, where you would define a "class" value rather than a "classes" value, e.g. style_formats: [ { title: 'Table row 1', selector: 'tr', class: 'tablerow1' } ] But PW's implementation of TinyMCE doesn't provide a way to directly control this setting and instead parses the contents of the "Custom style formats CSS" config textarea into the style_formats setting. Situations like this are why I think PW should provide a hookable method allowing the array of data that becomes the TinyMCE settings to be modified at runtime, as mentioned in this issue: https://github.com/processwire/processwire-issues/issues/1981
- 1 reply
-
- 4
-
You might be experiencing this issue: https://github.com/processwire/processwire-issues/issues/1952 https://github.com/processwire/processwire-issues/issues/1974 To fix you can update to the latest PW dev version so as to get this commit, or change this line of .htaccess to: RewriteRule ^(.*)$ index.php?it=$1 [L,QSA,UnsafeAllow3F]
- 1 reply
-
- 3
-
I needed to do this and thought the code might be useful for others too. In my case the organisation has a main site (Site A) and a related but separate site (Site B). The objective is for the users at Site B to be automatically kept in sync with the users of Site A via PW multi-instance. Users are only manually created or deleted in Site A. Both sites have the same roles configured. // InputfieldPassword::processInput $wire->addHookAfter('InputfieldPassword::processInput', function(HookEvent $event) { /** @var InputfieldPassword $inputfield */ $inputfield = $event->object; $input = $event->arguments(0); /** @var UserPage $page */ $page = $inputfield->hasPage; if($page->template != 'user') return; // Return early if there are any password errors if($inputfield->getErrors()) return; // Get the new password as cleartext from $input $pass = $input->get($inputfield->name); if(!$pass) return; // Set the password as a custom property on the Page object $page->newPass = $pass; }); // Pages::saved $pages->addHookAfter('saved', function(HookEvent $event) { /** @var UserPage $page */ $page = $event->arguments(0); if($page->template != 'user') return; if($page->isUnpublished()) return; // Update or create user in Site B $site_b = new ProcessWire('/home/siteb/siteb.domain.nz/', 'https://siteb.domain.nz/'); /** @var UserPage $u */ $u = $site_b->users->get($page->name); // Create a new user if none exists with this name if(!$u->id) $u = $site_b->users->add($page->name); // Set the password if the custom property was set in the InputfieldPassword::processInput hook if($page->newPass) $u->pass = $page->newPass; // Set email address $u->email = $page->email; // Set roles $u->roles->removeAll(); foreach($page->roles as $role) { $u->addRole($role->name); } $u->save(); }); // Pages::deleteReady $pages->addHookAfter('deleteReady', function(HookEvent $event) { /** @var Page $page */ $page = $event->arguments(0); if($page->template != 'user') return; // Delete user in Site B $site_b = new ProcessWire('/home/siteb/siteb.domain.nz/', 'https://siteb.domain.nz/'); $u = $site_b->users->get($page->name); if(!$u->id) return; $site_b->users->delete($u); }); This assumes the use of the default "user" template and not an alternative template. In my case the user template only has the default fields, but the code could be adapted if you have additional fields in your user template. This doesn't handle renaming of users as that's not something I have a need for. But there would be ways to achieve this too, e.g. store the user ID for Site B in a field on the user template in Site A, and then get the Site B user by ID rather than name.
-
You can do something like this: $wire->addHookBefore('Inputfield::render', function(HookEvent $event) { /** @var Inputfield $inputfield */ $inputfield = $event->object; $process = $this->wire()->process; // Return early if this is not ProcessPageEdit if(!$process instanceof ProcessPageEdit) return; // The page being edited $page = $process->getPage(); // The field associated with the inputfield, if any // Useful for when the inputfield is in a repeater, as the inputfield name will have a varying suffix $field = $inputfield->hasField; // The page that the inputfield belongs to // Useful for identifying if the inputfield is in a repeater $inputfield_page = $inputfield->hasPage; // Return early if this is not a page we are targeting if($page->template != 'test_combo') return; // Do some check to identify the inputfield by name or field name if($field && $field->name === 'text_1' && $inputfield_page->template == 'repeater_test_repeater') { // Check some other field value if the message depends on it if($page->test_combo->my_date === '2024-10-18 00:00:00') { // Show an error message $inputfield->error('This is a test error message'); } } // Do some check to identify the inputfield by name or field name if($inputfield->name === 'test_combo_my_date') { // Check some other field value if the message depends on it if($page->test_repeater->first()->text_1 === 'hello') { // Show an error message $inputfield->error('Another test error message'); } } });
-
@nurkka, when I test here DelayedImageVariations is sort of working with webp(), although I'm surprised it works at all because I thought it would be a case like the one mentioned in the readme: I thought the webp() method would need an actual resized variation to be available at the time it is called. But I'm testing like this... foreach($page->images as $image) { $image_url = $image->size(250,250)->webp()->url; bd($image_url, "image_url"); echo "<img src='$image_url' alt=''>"; } ...and what I experience is that on the first page load the webp()->url results in a JPG file... ...and on subsequent page loads it results in a WebP file. I don't get any 404s or broken images, and the only effect is slightly larger file sizes on the first page load, which isn't that big of a deal. But if you experience something different then I don't have a solution within DelayedImageVariations, sorry. My suggestion then would be to pursue a different strategy to pre-generate your image variations rather than use DelayedImageVariations. You could generate the variations on page save. See this post for how you could do it without slowing down page saves in the admin:
-
Problem with Page Autocomplete using findReady hook not saving data
Robin S replied to Kiwi Chris's topic in General Support
Since PW 3.0.238 you can do this: $wire->addHookAfter('ProcessPageSearch::findReady', function(HookEvent $event) { /** @var ProcessPageSearch $pps */ $pps = $event->object; $selector = $event->return; $for_selector_name = $event->wire()->input->get('for_selector_name'); if($for_selector_name) { $data = $pps->getForSelector($for_selector_name, true); // $data includes the PageAutocomplete field name and the ID of the edited page // Do something with $selector... } }); -
Problem with Page Autocomplete using findReady hook not saving data
Robin S replied to Kiwi Chris's topic in General Support
I think the key thing will be to make sure the selector string you've defined in the field settings does not exclude any pages that you might want to include in the modified selector coming from your findReady hook. In other words, any selector in the settings should be broader than the selector from the hook. This is because any pages set to the inputfield will be validated against the field settings on save. I would make the field settings very broad (e.g. just a template) and then narrow this in your hook. -
Not sure what you mean here. The ProcessWire admin for non-superusers is the most minimal CMS back-end I've seen. It's just the page tree, which is easily understood even by beginners because it corresponds to the front-end structure. And from the page tree editors can only edit the pages that have the templates you allow for them. If the page tree is still too overwhelming you customise it with hooks. If the editors only need to deal with pages in a particular branch of the tree you can conditionally set the top-level parent of the tree. $wire->addHookBefore('ProcessPageList::execute', function(HookEvent $event) { /** @var ProcessPageList $ppl */ $ppl = $event->object; if($event->wire()->page->process !== 'ProcessPageList') return; if($event->wire()->config->ajax) return; // If the user has the "editor" role... if($event->wire()->user->hasRole('editor')) { // Limit Page List to only show a particular page and its descendants $ppl->id = 1085; } }); Or for more complex situations you can control which pages are "listable" individually:
-
My pleasure. The hooks and inputfields APIs in ProcessWire make module development an absolute dream. It's very satisfying seeing the results you can get with just a little code, and working on modules provides a motivation to dig into the core code so I learn a lot in the process. Also, another shout out to @adrian's amazing Tracy Debugger, which has been transformative for my coding. I have several more modules in progress so watch this space. 🙂
- 11 replies
-
- 30