Jump to content

Robin S

Members
  • Posts

    4,791
  • Joined

  • Days Won

    303

Everything posted by Robin S

  1. Version 0.1.3 is released. This adds a button to generate all currently queued variations: The readme is also updated to add some important notes about 404 configuration in .htaccess and ProCache configuration.
  2. I made some updates in v0.1.1 so that unprocessed queue files get deleted if the original Pageimage is deleted. That sounds like a simple solution. In v0.1.1 the queue file is just the variation URL with ".txt" at the end. So for a variation that will have a URL "/site/assets/files/1234/myimage.500x500.jpg" once it is created the queue file would be at "/site/assets/files/1234/myimage.500x500.jpg.txt". So in your loadFilesOnDemand() method you could check if DelayedImageVariations is installed and if so check for the existence of the queue file in addition to the variation file. @bernhard, in v0.1.2 I've changed the queue file extension to ".queue" because it will allow me to identify the queue files more efficiently for another feature I have in mind to release soon. So the section in strikethrough above will now be: In v0.1.2 the queue file is just the variation URL with ".queue" at the end. So for a variation that will have a URL "/site/assets/files/1234/myimage.500x500.jpg" once it is created the queue file would be at "/site/assets/files/1234/myimage.500x500.jpg.queue".
  3. Delayed Image Variations Delays the creation of image variations until their individual URLs are loaded. Image variations being generated one-by-one: Background Normally when you create new image variations in a template file using any of the ProcessWire image resizing methods, all the new variations that are needed on a page will be created from the original Pageimage the next time the page is loaded in a browser. If there are a lot of images on the page then this could take a while, and in some cases the page rendering might exceed your max_execution_time setting for PHP. So you might like to have image variations be generated individually when they are requested rather than all at once. That way the page will render more quickly and the risk of a timeout is all but eliminated. But there can be problems with some implementations of this approach, such as with the (in)famous TimThumb script: It's not ideal to have PHP be involved in serving every image as this is needlessly inefficient compared to serving static assets. It's not good to allow arbitrary image sizes to be generated by varying URL parameters because you might want to restrict the maximum resolution an image is available at (e.g. for copyrighted images). If images are generated from URL parameters a malicious user could potentially generate thousands of images of slightly different dimensions and fill up all your disk space. The Delayed Image Variations module avoids these problems - it creates variations when their URLs are loaded but only allows the specific dimensions you have defined in your code. It does this by saving the settings (width, height and ImageSizer options) of every new Pageimage::size() call to a queue. The module intercepts 404s and if the request is to an image variation that doesn't exist yet but is in the queue it generates the variation and returns the image data. This only happens the first time the image is requested - after that the image exists on disk and gets loaded statically without PHP. Usage In most cases usage is as simple as installing the module, and you don't need to change anything in your existing code. However, there might be some cases where you don't want the creation of a particular image variation to be delayed. For example, if you created a variation in your code and then immediately afterwards you wanted to get information about the variation such as dimensions or filesize. $resized = $page->image->width(600); echo $resized->height; echo $resized->filesize; This wouldn't work because the actual creation of the resized image hasn't happened yet and so that information won't be available. So in these cases you can set a noDelay option to true in your ImageSizer options and Delayed Image Variations will skip over that particular resizing operation. $resized = $page->image->width(600, ['noDelay' => true]); echo $resized->height; echo $resized->filesize; For advanced cases there is also a hookable method that you can return false for if you don't want a delayed variation for any particular resizing operation. Example: $wire->addHookAfter('DelayedImageVariations::allowDelayedVariation', function(HookEvent $event) { /** @var Pageimage $pageimage */ $pageimage = $event->arguments(0); // The Pageimage to be resized $width = $event->arguments(1); // The width supplied to Pageimage::size() $height = $event->arguments(2); // The height supplied to Pageimage::size() $options = $event->arguments(3); // The options supplied to Pageimage::size() // Don't delay variations if the Pageimage belongs to a page with the product template if($pageimage->page->template == 'product') $event->return = false; }); 404 handling For Delayed Image Variations to work your .htaccess file needs to be configured so that ProcessWire handles 404s. This is the default configuration so for most sites no change will be needed. # ----------------------------------------------------------------------------------------------- # 2. ErrorDocument settings: Have ProcessWire handle 404s # # For options and optimizations (O) see: # https://processwire.com/blog/posts/optimizing-404s-in-processwire/ # ----------------------------------------------------------------------------------------------- ErrorDocument 404 /index.php ProCache If you are using ProCache then make sure it is not configured to cache the 404 page or else PHP will not execute on 404s and queued image variations will not be generated. Generate queued variations Before launching a new website you might want to pre-generate all needed image variations, so no visitor will have to experience a delay while a variation is generated. To queue up the image variations needed for your site you will need to visit each page of the website one way or another. You could do this manually for a small site but for larger sites you'll probably want to use a site crawler tool such as Xenu's Link Sleuth. This may generate some image variations but it's likely that some other variations (e.g. within srcset attributes) will not be requested and so will remain queued. To generate all currently queued variations there is a button in the module config: This will search the /site/assets/files/ directory for queue files and render the variations. https://github.com/Toutouwai/DelayedImageVariations https://processwire.com/modules/delayed-image-variations/
  4. Does anyone know of a way to prompt a file download from code that is executed in the Tracy Console panel? When I try things that would normally prompt a download if executed in a template file, such as... header('Content-type: text/csv'); header("Content-Disposition: attachment; filename=myfile.csv"); // ... ...or... $files->send($myfile, ['forceDownload' => true]); ...the output is always sent directly to the Console panel and no download is prompted. No big deal if it's not possible but sometimes it would be handy to export some data or files in the form of a download using the Console panel. Maybe @adrian or anyone else knows a solution for this? Thanks in advance.
  5. Awesome, thanks for creating this @BitPoet! I am going to be locked into CKEditor for the foreseeable future because in addition to my public modules I have a number of private modules that integrate with CKEditor and rebuilding them all for TinyMCE will be a big job. And for the types of sites I work on I don't see many advantages of TinyMCE over CKEditor so I don't have much motivation to do all the rebuilding at the moment - I'll probably get to it eventually but not any time soon. So it's great that HannaCodeDialogTiny is available for anyone who wants to switch to TinyMCE sooner than I do.
  6. Sounds quite specific to your particular use case, but it was easy to support so in v0.1.2 I've added a checkbox in the module config to not show the menu. Thanks for pointing this out - it's now collapsed in v0.1.2 as that info isn't something that non-superusers need to be bothering themselves with. I forget that PW has this open by default because I use the AdminOnSteroids option that automatically collapses it. Too niche to bother with in the module config. It can be translated if needed, either in the core translations for multi-language sites or via wireLangReplacements() in site/ready.php wireLangReplacements([ 'Modules' => ['My menu title', 'LimitedModuleEdit'], ]);
  7. For any future readers of this thread, here is a module for this purpose:
  8. @MarkE, I've released a module that allows non-superusers to configure selected modules, which might be helpful for your current project:
  9. Limited Module Edit Allows non-superusers to edit a limited selection of modules. Of course, there are good reasons why non-superusers are normally not allowed to access the configuration screen of modules so use this module with caution. Usage 1. Install Limited Module Edit. 2. In the module configuration select one or more modules in the "Modules enabled for limited editing" field. When you enable a module here a corresponding "lme" permission is installed. For example, if WireMailSmtp is enabled here then a permissioned named "lme-wire-mail-smtp" will be installed. 3. For any role that you want to allow to configure the previously selected modules, enable the "module-admin" permission and the "lme" permissions for any module they may configure. 4. Users with these permissions will now see a special Modules section in the main menu that provides links to configure only the modules they have been given permission for. These users are not allowed to install modules nor are they allowed to uninstall the modules they have permission to configure. https://github.com/Toutouwai/LimitedModuleEdit https://processwire.com/modules/limited-module-edit/
  10. No, not unless the core image field supported avif format at some point in the future. This module doesn't change which file formats are supported by an images field.
  11. I like to do that too - show the page ID and also the template name in the page list. I do that via a private module which isn't installed here as it would just confuse things for this demo. But when I'm entering an ID into some API code I feel safer if I'm copying and pasting rather than memorising and typing the ID in manually, particularly on larger sites where the IDs are getting up into 6 digits and it's easy to misread or transpose the digits.
  12. InputfieldFile has several settings that don't have config fields in the admin. See here: https://github.com/processwire/processwire/blob/5609935e4ee96611965550e57d3139200de95c35/wire/modules/Inputfield/InputfieldFile/InputfieldFile.module#L20-L26 I'm not sure of the reasons why but perhaps the thinking is that they would only needed for specialised uses of the inputfield. You could use a hook in /site/ready.php to add a config field for that setting to all files fields if you want to set it per field: $wire->addHookAfter('InputfieldFile::getConfigInputfields', function(HookEvent $event) { /** @var InputfieldFile $inputfield */ $inputfield = $event->object; /** @var InputfieldWrapper $wrapper */ $wrapper = $event->return; /** @var InputfieldCheckbox $f */ $f = $event->wire()->modules->get('InputfieldCheckbox'); $f->name = 'noShortName'; $f->label = 'Disable abbreviated filenames'; $f->label2 = 'Disable abbreviated filenames in inputfield'; $f->collapsed = Inputfield::collapsedBlank; $f->checked($inputfield->noShortName); $wrapper->add($f); }); Or if you want to disable it for all file fields: $wire->addHookAfter('InputfieldFile::renderReadyHook', function(HookEvent $event) { /** @var InputfieldFile $inputfield */ $inputfield = $event->object; $inputfield->noShortName = true; });
  13. When writing API code I often refer to the PW admin to get particular page IDs or field names. And when I'm writing client instructions I often need to insert the labels of particular fields. To make this quicker and more convenient I added some custom JavaScript to the PW admin that copies these things to the clipboard on Alt + click and Ctrl + click. The Page List item and inputfield header are briefly highlighted in yellow to signify that the copying has occurred. This is tested in Windows and I'm not sure if the Alt key / Ctrl key detection is the same for other operating systems but you could adjust the key detection as needed. In /site/ready.php // Add custom JS file to $config->scripts FilenameArray // This adds the custom JS fairly early in the FilenameArray which allows for stopping // event propagation so clicks on InputfieldHeader do not also expand/collapse InputfieldContent $wire->addHookBefore('ProcessController::execute', function(HookEvent $event) { // Optional: for superuser only if(!$event->wire()->user->isSuperuser()) return; $config = $event->wire()->config; $modified = filemtime($config->paths->templates . 'admin-assets/copy-on-click.js'); $js_url = $config->urls->templates . "admin-assets/copy-on-click.js?m=$modified"; $config->scripts->add($js_url); }); In /site/templates/admin-assets/copy-on-click.js $(document).ready(function() { // Copy a string to the clipboard function copyToClipboard(string) { const $temp = $('<input type="text" value="' + string + '">'); $('body').append($temp); $temp.select(); document.execCommand('copy'); $temp.remove(); } // Copy page ID when Page List row is Alt + clicked $(document).on('click', '.PageListItem', function(event) { if(event.altKey) { const classes = $(this).attr('class').split(' '); for(const item of classes) { if(item.startsWith('PageListID')) { const id = item.replace('PageListID', ''); copyToClipboard(id); $(this).effect('highlight', {}, 500); break; } } } }); // When InputfieldHeader is clicked $(document).on('click', '.InputfieldHeader', function(event) { let text = ''; // If Alt + clicked then copy the input name the label is for, or the ID as a fallback if(event.altKey) { event.preventDefault(); event.stopImmediatePropagation(); text = $(this).attr('for'); if(!text) text = $(this).parent().attr('id'); text = text.replace(/^Inputfield_|wrap_Inputfield_|wrap_/, '').trim(); } // If Ctrl + clicked then copy the label text else if(event.ctrlKey) { event.preventDefault(); event.stopImmediatePropagation(); text = $(this).text().trim(); // If AdminOnSteroids is installed use the below instead to exclude text within the AOS field edit link // text = $(this).clone().find('.aos_EditField').remove().end().text().trim(); } if(text) { copyToClipboard(text); $(this).effect('highlight', {}, 500); } }); }); Demo (using the Tracy console only as a convenient place to paste into for demonstration): Copying the field label is useful for getting the name of config fields too, for when you need them in your API code.
  14. If you have only one WireMail module installed it is used for all email sent by ProcessWire. If you have multiple WireMail modules installed there are ways you can choose which to use in any given case. https://processwire.com/modules/wire-mail-router/
  15. @Murray, did you take a look through the modules directory? https://processwire.com/modules/category/email/ https://processwire.com/modules/wire-mailgun/ https://processwire.com/modules/wire-mail-send-grid/
  16. Yes, it's because of the ProcessWire namespace. Add it when setting the function name to your variable: $func = 'ProcessWire\foo';
  17. Seeing as this only affects the specific case when you (the developer) are debugging 404s for URLs that PW doesn't allow, maybe the solution is just to temporarily modify the PW .htaccess for the debugging session. If you are on a local hosting or a dev site that doesn't have public access you can simply comment out rule 16A: # RewriteCond %{REQUEST_URI} "^/~?[-_.a-zA-Z0-9/]*$" And if on a public site you could use a more permissive redirect just for your own IP address by adding this immediately after RewriteEngine On: # Use a less restrictive redirect just for my own trusted IP address RewriteCond %{REMOTE_ADDR} ^206\.83\.102\.77 RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?it=$1 [L,QSA] When you're finished you'd revert the .htaccess to how it was before. This seems good enough to me, unless you can see a downside.
  18. Thanks for looking into this @adrian This didn't work for me. $_SERVER['HTTP_HOST'] and location.hostname just give me "mywebsite.com" and without the "https://" it doesn't form a valid base for the URL. Simply using "/" in each file worked. Or for an absolute path to the root maybe $_SERVER['HTTP_ORIGIN'] and location.origin would work. Maybe with a trailing slash added? I'm out of my depth here, but would it be a problem when the script that is executing is not in the site root? Some cases of this might be: 1. When Tracy is being used outside of ProcessWire and the executing script is /some-directory/some-file.php rather than everything being executed from an index.php 2. When PW is installed in a subdirectory and so index.php is not in the site root 3. When PW is bootstrapped from /some-directory/some-file.php
  19. @Jim Bailie, if you update the module to v0.2.3 there is a hookable method that fires when a file is about to be replaced. $wire->addHookAfter('FilesRenameReplace::replaceReady', function(HookEvent $event) { /** @var InputfieldFile $inputfield */ $inputfield = $event->arguments(0); /** @var Pagefile $pagefile */ $pagefile = $event->arguments(1); /** @var Pagefile $replacement */ $replacement = $event->arguments(2); // Do something here... }); I don't think you could do anything useful to the Pagefile objects at this point given that the original file is about to be deleted and the replacement file is about to have all its properties overwritten from the original file, but you could set some other field value on the page like this: $wire->addHookAfter('FilesRenameReplace::replaceReady', function(HookEvent $event) { /** @var InputfieldFile $inputfield */ $inputfield = $event->arguments(0); /** @var Pagefile $pagefile */ $pagefile = $event->arguments(1); /** @var Pagefile $replacement */ $replacement = $event->arguments(2); // Set a date field on the page $page = $inputfield->hasPage; if($page && $page->id) { $page->setAndSave('my_date_field', time()); } });
  20. Those template files need a comment that explains what is going on. I opened a GitHub issue: https://github.com/processwire/processwire-issues/issues/1806
  21. If item 2 is enabled in .htaccess then PW will still handle 404s for URLs that don't conform to its rules so you don't necessarily need to change items 16A or 16B. You could do something like this in /site/init.php: $wire->addHookBefore('ProcessPageView::pageNotFound', function(HookEvent $event) { $info = pathinfo($_SERVER['REQUEST_URI']); // Redirect or do whatever if(!empty($info['extension']) && strtolower($info['extension']) === 'pdf') { $event->wire()->session->location("/find-file/?filename={$info['basename']}"); } }); Unfortunately is seems that Tracy Debugger doesn't work on this kind of 404 which makes debugging harder, but I've asked about this in the Tracy subforum and @adrian might have a solution.
  22. Hi @adrian, If I dump something in the template file for my 404 page, or within a hook to ProcessPageView::pageNotFound, then I can see the debug bar and the dump when the requested URL is one that passes PW's rules in .htaccess, e.g. https://mywebsite.com/this-page/does-not-exist/ But if the URL doesn't conform to PW's rules... https://mywebsite.com/this-page/doesn't-exist/ ...then I still get a 404 page that is managed by PW and the associated template file (assuming item 2 is enabled in .htaccess) but there is no debug bar or dump. Is it possible to have the Tracy debug bar in this situation?
×
×
  • Create New...