-
Posts
5,034 -
Joined
-
Days Won
340
Everything posted by Robin S
-
Hooks inside init.php to namespaced classes does not work [SOLVED]
Robin S replied to Juergen's topic in API & Templates
Here is the relevant part of the docs for reference: https://processwire.com/docs/modules/hooks/#how-can-i-define-my-own-hookable-methods -
Why would the pages of a template be invisible in the non-default language?
Robin S replied to da²'s topic in API & Templates
I guess it's expected because it's been observed since 2013 at least. Discussion and code snippets in this topic: -
It's not included in the core. It's currently part of the ProFields bundle but that might change in future.
-
Hooks inside init.php to namespaced classes does not work [SOLVED]
Robin S replied to Juergen's topic in API & Templates
I didn't read this thread closely but I see you are calling $this->___renderAsterisk() https://github.com/juergenweb/FrontendForms/blob/9ea92a986528a96e2aeb875482967b81e8a50018/Formelements/Textelements/Label.php#L59 If you want hooks to fire you need to call it without the underscores: $this->renderAsterisk() -
@gornycreative, please try v0.1.1 and if the issue isn't fixed let me know.
-
Hi @adrian, I updated an older site running PHP 7.1 to the latest Tracy Debugger and got this error: Maybe that line needs a check of which Tracy version is in use?
- 1 reply
-
- 1
-
-
@ryan, the main branch is at 3.0.244 but the dev branch is still at 3.0.243. Does the dev version number need an update?
-
No, everything is good. A really useful set of features, thanks!
-
@adrian, thanks, the history is working for me now. I think this is caused by a combination of the button height being in fractional pixels and the scaleX(-1) transform on the right arrow. This causes Chrome to round the two arrow buttons to different numbers of whole pixels. There would be a several different ways to solve this, but perhaps the easiest thing would be to use the FontAwesome right arrow character for second arrow button rather than flipping a left arrow character. You'd also then tweak the margin and border on that button seeing as it would no longer be flipped. Leaving the coloured border on all sides and adjusting to margin-left: -12px looks good to me.
-
This is awesome, thanks! A few things I noticed when testing: 1. After updating from a previous TracyDebugger version, the console window is only 1 line high and there's an error in the browser console. Probably a browser cache issue because if I do a hard reload the issues are gone. 2. Is it expected that clicking on a snippet that's already open in the console will open another copy of the snippet? Perhaps instead it should focus the already open tab? 3. The "Go Back" arrow never seems to become activated after executions or changes to the code. It's always greyed out for me. 4. Very minor and I think it's not a new thing, but for some reason the right arrow button is 1 pixel higher than the left arrow button.
-
Unfortunately I don't think this module can be easily adapted to support multi-language menus, because to get the repeater-like interface for variable numbers of child items working I needed to come up with a custom way to store that data in JSON format rather than use the core way of storing individual inputfield data. So multi-language support would mean creating a new way of storing multi-language data that's separate from PW's way and I don't want to try to reinvent that wheel. But you could hook some of the same methods that the module does to add your own custom menus to the admin. Example: $wire->addHookBefore('ProcessController::execute', function(HookEvent $event) { // Prevent admin menus from being cached $this->wire()->session->removeFor('AdminThemeUikit', 'prnav'); $this->wire()->session->removeFor('AdminThemeUikit', 'sidenav'); }); $wire->addHookAfter('AdminThemeFramework::getPrimaryNavArray', function(HookEvent $event) { $items = $event->return; $user = $event->wire()->user; $data = [ [ 'label' => [ 'default' => 'Shirts', 'french' => 'Chemises', ], 'url' => [ 'default' => '/shirts/', 'french' => '/chemises/', ], 'children' => [ [ 'label' => [ 'default' => 'Small', 'french' => 'Petit', ], 'url' => [ 'default' => '/shirts/small/', 'french' => '/chemises/petit/', ], 'icon' => 'smile-o', ], [ 'label' => [ 'default' => 'Medium', 'french' => 'Moyen', ], 'url' => [ 'default' => '/shirts/medium/', 'french' => '/chemises/moyen/', ], 'icon' => 'thumbs-o-up', ], ], ], ]; foreach($data as $item) { $menu = [ 'id' => 0, 'parent_id' => 0, 'name' => '', 'title' => $item['label'][$user->language->name], 'url' => $item['url'][$user->language->name], 'icon' => '', 'children' => [], 'navJSON' => '', ]; foreach($item['children'] as $child) { $menu['children'][] = [ 'id' => 0, 'parent_id' => 0, 'name' => '', 'title' => $child['label'][$user->language->name], 'url' => $child['url'][$user->language->name], 'icon' => $child['icon'], 'children' => [], 'navJSON' => '', ]; } $items[] = $menu; } $event->return = $items; });
-
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
-
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.
-
- 5
-
-
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.