Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 11/03/2023 in all areas

  1. This week I've been working on various ProcessWire related projects, but haven't pushed much to the core. There was a core feature I've been working on which I decided to instead put in a module. It's one of those things that should be be really beneficial for some people, but not necessarily needed by everyone, so it makes more sense as a module. This particular module expands upon the page-lock option and permission in ProcessWire. The page-lock option (which you'll see as the "Lock" status in the Settings tab of the page editor) provides the ability to lock a page for edits. This can be really useful if you want to prevent a particular page from being modified for whatever reason. For instance, maybe you are doing a $pages->get('/some/page/'); on the API side and if the path /some/page/ got changed, it would break something in the site. So to prevent clients from breaking the site, you lock the page to prevent them from screwing it up and breaking something on the site. This is quite useful, and often a life saver. But I don't use it as much as I'd like because of one downside. That downside is that it locks the entire page so that nothing on it can be edited. So it's just too heavy of a lock. What if you just wanted to lock the page so that the name, title and parent couldn't be edited, but everything else could be? That's what this new module enables. To lock a field in the page editor, you click its header and hold until a dialog pops up asking if you want to lock it. To unlock, you do the same thing. Once a field is locked, it remains locked (non-editable) until unlocked. Only users with page-lock permission on the page can lock or unlock fields. Locks can also be managed with checkboxes in the page editor Settings tab as well, just in case that is more convenient in some contexts. While these are editor locks rather than API locks, the locks do affect contexts outside the page editor too, such as actions in the page list. For instance, if you locked "parent" then you wouldn't be able to bypass it dragging a page in the Page List. I finished developing the module today, but I've not yet written documentation for it or uploaded to GitHub, etc., so I'm going to give it another day of work and testing before releasing it next week, and will cover more details in next week's post. Thanks and have a great weekend!
    11 points
  2. Generate image placeholders for smoother lazyloading. Currently supports ThumbHash, BlurHash, and average color placeholders. I've been using the wonderful ImageBlurhash module for this in the past, but unfortunately it's no longer in active development. This new module adds ThumbHash and Average Color placeholder algorithms, improves performance by caching generated placeholders, fixes an issue when replacing images, and allows regenerating and clearing placeholders via the admin interface. Try it out using the installation instructions below or check out the GitHub repo for details. Why use image placeholders? Low-Quality Image Placeholders (LQIP) are used to improve the perceived performance of sites by displaying a small, low-quality version of an image while the high-quality version is being loaded. The LQIP technique is often used in combination with progressive lazyloading. How it works This module will automatically generate a small blurry image placeholder for each image that is uploaded to fields configured to use them. In your frontend templates, you can access the image placeholder as a data URI string to display while the high-quality image is loading. See below for markup examples. Placeholder types The module supports generating various types of image placeholders. The recommended type is ThumbHash which encodes most detail and supports transparent images. ThumbHash is a newer image placeholder algorithm with improved color rendering and support for transparency. BlurHash is the original placeholder algorithm, developed at Wolt. It currently has no support for alpha channels and will render transparency in black. Average color calculates the average color of the image. Installation Install the module using composer from the root of your ProcessWire installation. composer require daun/processwire-image-placeholders Open the admin panel of your site and navigate to Modules → Site → ImagePlaceholders to finish installation. Configuration You'll need to configure your image fields to generate image placeholders. Setup → Fields → [images] → Details → Image placeholders There, you can choose the type of placeholder to generate. If you're installing the module on an existing site, you can also choose to batch-generate placeholders for any existing images. Usage Accessing an image's lqip property will return a data URI string of its placeholder. $page->image->lqip; // data:image/png;base64,R0lGODlhEAAQAMQAA Accessing it as a method allows setting a custom width and/or height of the placeholder. $page->image->lqip(300, 200); // 300x200px Markup Using a lazyloading library like lazysizes or vanilla-lazyload, you can show a placeholder image by using its data URI as src of the image. <!-- Using the placeholder as src while lazyloading the image --> <img src="<?= $page->image->lqip ?>" data-src="<?= $page->image->url ?>" data-lazyload /> Another technique is rendering the placeholder and the original image as separate images on top of each other. This allows smoother animations between the blurry unloaded and the final loaded state. <!-- Display placeholder and image on top of each other --> <div class="ratio-box"> <img src="<?= $page->image->lqip ?>" aria-hidden="true"> <img data-src="<?= $page->image->url ?>" data-lazyload> </div>
    3 points
  3. Bonus! I've added an option to enable "Translate to all languages" for each Inputfield ? Enable the new translation button on the module config page. The old style of translation (translating each language from the default language) is still available for those who want to use it. Translate to all languages at once from the default language Translate to all languages at once from any language. This is where the tab indicators come in really handy to indicate the tabs that have received updated/translated content with one click. This is on the dev branch as well, so give it a try and tell me what you think.
    3 points
  4. I'm thrilled to announce the official release of RockPageBuilder, the game-changing tool that's set to transform your web development journey (at least ChatGPT says so ??)! With its brand new drag-and-drop interface RockPageBuilder is your secret weapon for creating outstanding ProcessWire-based websites. Get a taste of the future of web development by visiting the demo page at https://pagebuilder.baumrock.com/ and exploring the RockPageBuilder documentation at https://www.baumrock.com/en/processwire/modules/rockpagebuilder/docs/ Don't miss out on this exciting opportunity to elevate your web development game. Get ready to rock with RockPageBuilder! ??️ Early Bird Sales until 30.11. https://www.baumrock.com/processwire/module/rockpagebuilder/ Here is a quick demo video: And here is how to install it from scratch in under 5 minutes: Some showcase projects are already in the pipeline ? So be sure to subscribe to https://processwire.rocks/ or to https://www.baumrock.com/rock-monthly/ Have a great weekend!
    1 point
  5. Hey there, born out of a personal need I've implement a lightweight version of @Robin S' Hanna Code Dialog module for TinyMCE. In a bout of creativity, I've named it HannaCodeDialogTiny This module is still in alpha state and needs some extensive testing. If you encounter any problems, please open an issue on GitHub. It has no select options, descriptions or cheat sheets (yet), and it doesn't cope well with nested Hanna Codes. What it does have is the Insert Hanna Code dropdown in the TinyMCE menu bar with dialog-based insertion, non-editable Hanna Codes in the editor, double click on existing codes for editing in a dialog. Hanna Codes are also highlighted, and you can drag and drop them around. The dropdown: Double click on any highlighted Hanna Code: Fill in your values: The Hanna Code has been changed: Have fun!
    1 point
  6. Sounds like a useful module. Could this help with a related issue to locks I've had in that in ListerPro (or other places), I've wanted to have locked pages, but allow users to duplicate them? Imagine a scenario where someone has repeat orders and wants to make new orders that are very similar to previous ones with a few changes, so they should be able to duplicate an existing order, but not change it. I'm fine with changing the lock status via api on creation of the duplicate, but I've struggled with enabling the icon to click to allow copying a locked page.
    1 point
  7. Yes. myrace is just an inputfield that we added during runtime. It is not a field of the page, so $page->myrace will not work. But it is an inputfield of the form that is submitted, so the input post data will have that information available and we can use it for our further processing.
    1 point
  8. Just tried it and the new link feature is absolutely awesome. That saves so much time when translating content! Thank you very much. Translate to all is also nice, thanks! ?
    1 point
  9. Only used OneLogin so far. It's been a couple of years since I set this thing up, but as far as I can remember there was no need to tweak anything in advanced settings ?
    1 point
  10. Thx for the additions ? That would be a great use case for using $page->meta() ! It's already there without doing anything and it's also a lot easier to manipulate meta data from within a hook than updating a hidden field's content. Everything needed is doable with just a few lines of code without any modules. The modules do not help here. Quite the contrary, they make things more complicated and less robust. To add a runtime markup field to page edit: <?php $wire->addHookAfter("ProcessPageEdit::buildForm", function (HookEvent $event) { /** @var InputfieldForm $form */ $form = $event->return; $page = $event->process->getPage(); // custom rules where to add the field // eg add it only to pages with template "home" // otherwise exit early and do nothing if ($page->template !== 'home') return; $form->insertAfter([ 'type' => 'markup', 'name' => 'mymarkup', // we need that later ;) 'value' => '<h1>I am a custom markup field</h1>', ], $form->get('title')); }); In this markup field you can show any HTML/PHP markup you want. Now we can also add dynamic selects - also just a single and quite simple hook: <?php $wire->addHookAfter("ProcessPageEdit::buildForm", function (HookEvent $event) { /** @var InputfieldForm $form */ $form = $event->return; $page = $event->process->getPage(); // custom rules where to add the field // eg add it only to pages with template "home" // otherwise exit early and do nothing if ($page->template != 'home') return; // data coming from your file $races = ['foo', 'bar', 'baz']; // add all options $f = new InputfieldRadios(); $f->label = 'Choose your race'; $f->name = 'myrace'; foreach ($races as $race) { $f->addOption($race, "Use Race '$race' for something"); } // now add it after our markup field: $form->insertAfter($f, $form->get('mymarkup')); }); And finally we save the data: Another small hook ? <?php $wire->addHookAfter("Pages::saveReady", function (HookEvent $event) { // get the selected race from the radio input // we sanitize the input to make sure it is a string $race = $this->wire->input->post('myrace', 'string'); if (!$race) return; // save selected race to page meta data $page = $event->arguments(0); $page->meta('myrace', $race); }); Of course we have now two hooks for the same process, so we can combine those two to one and we end up with two hooks which should all you need: <?php $wire->addHookAfter("ProcessPageEdit::buildForm", function (HookEvent $event) { /** @var InputfieldForm $form */ $form = $event->return; $page = $event->process->getPage(); // custom rules where to add the field // eg add it only to pages with template "home" // otherwise exit early and do nothing if ($page->template != 'home') return; $race = $page->meta('myrace'); $time = $page->meta('chosenat') ?: ''; if ($time) $time = date("Y-m-d H:i:s", $time); $form->insertAfter([ 'type' => 'markup', 'name' => 'mymarkup', 'value' => '<h1 class=uk-margin-remove>I am a custom markup field</h1>' . "<p>Last Chosen Race: $race (@$time)</p>", ], $form->get('title')); // data coming from your file $races = ['foo', 'bar', 'baz']; // add all options $f = new InputfieldRadios(); $f->label = 'Choose your race'; $f->name = 'myrace'; foreach ($races as $race) { $f->addOption($race, "Use Race '$race' for something"); } // now add it after our markup field: $form->insertAfter($f, $form->get('mymarkup')); }); $wire->addHookAfter("Pages::saveReady", function (HookEvent $event) { // get the selected race from the radio input // we sanitize the input to make sure it is a string $race = $this->wire->input->post('myrace', 'string'); if (!$race) return; // save selected race to page meta data $page = $event->arguments(0); $page->meta('myrace', $race); $page->meta('chosenat', time()); }); No modules, no rocket science. Just ProcessWire awesomeness ?
    1 point
  11. As @bernhardwrote, it is pretty doable. In addition to the markup field, I'd also add two hidden fields to the template to: store the parsed data (textarea) indicate we need to make a choice (checkbox) In a Pages::saveReady hook, I'd check if the file field has changed. If yes, parse the contents, and either: a) assign the page fields if there is only one race present; b) or fill the textarea with the parsed data (probably json encoded) and set needsChoice to 1. If the file field hasn't changed, needsChoice is 1 and a choice was sent, wake up the data from the textarea, pick the chosen race and fill your fields. Then set needsChoice to 0. In a ProcessPageEdit::buildForm hook, I'd check if needsSelection is set, and if yes, I'd fill the markup field with the race selection radio input. (Instead of the markup field, one could even use a regular InputfieldRadios and insert that into the form). It also has the charm that you can put "needsChoice!=1" in your selectors to see all unfinished multi-race pages. Two hooks, three fields, done.
    1 point
  12. This is where you make it more complicated than it needs to be ? You don't need to cancel the save at any stage. You just need to make sure that only the correct values are written to a dedicated field of your page. But there's nothing bad in having the file stored in one field, then process that file on save, then let the user choose the correct race and then on the next save you write the correct race to the dedicated field that only stores one race. This would be fairly easy to achieve with a custom markup field. There you process the file and display results, for example with a radio list element. The markup field could show some information like "this field will list all races from the uploaded file. please upload a file and save the page." After upload and save you present something like this: Once the user selects for example "race 2" and saves the page you take that information and save all the necessary data of race 2 to your page's dedicated fields and voila you always have the correct data in your pages and you don't need to revert anything or such. In general chances are high that this feeling is wrong ?
    1 point
  13. HannaCodeDialogTiny is now in the module directory.
    1 point
  14. This week there are a few updates on the dev branch. Since I'm short on time today, I'll just briefly cover the most interesting ones. Support for OR-groups, sub-selectors, and match same (1) @item groups (see last example at that link) have been added to ProcessWire's in-memory page matching selectors, as used primarily by the $page->matches() method. Previously these features were supported only by the database selectors from $pages->find() and methods that delegated to it. The $page->matches() method that gained these features is used by the core in various places for runtime matching of pages, such as when finding/filtering in a PageArray, for example. Support has also been added for OR-groups to the base Selectors class, which makes it possible to use OR-groups on non-Page objects too. These database-specific selector features were added because there's been a recurring request to support OR groups in places that currently use memory selectors, so this should do that. Though it'll remain just on the dev branch until it's had more thorough testing. While there will always be some differences between database and memory selectors, this does narrow the gap a bit. Thanks for reading and have a great weekend!
    1 point
  15. hi @Smirftsch my pleasure ? have a nice day
    1 point
  16. This week the ProcessWire core dev branch version has been bumped to 3.0.230. Currently we are about 10 commits ahead of the main/master branch. Relative to that branch, we have 5 issue fixes, 2 pull requests, major improvements to the wireIconMarkup() function and some minor improvements to the ProcessLogger module. We may merge these updates (among others) to the main/master branch as soon as next week. This week I also developed a new security module called LoginTimer that helps to prevent timing attacks in ProcessWire. Admittedly, I started this more for fun than anything, as I don't think timing attacks are a common problem in ProcessWire. But the more I got into it, the more I became aware of the potential dangers of timing attacks (particularly outside of the ProcessWire world). In any case, I now view it as an important security consideration and definitely thought we should have a module for it. Maybe someday we'll have it in the core too. The module is now available in the modules directory and on GitHub, and I wrote up a blog post to accompany the module and that is located here: https://processwire.com/blog/posts/timing-attacks-and-how-to-prevent-them/
    1 point
  17. Solution: https://processwire.com/api/ref/page/num-parents/
    1 point
×
×
  • Create New...