Jump to content

Robin S

  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by Robin S

  1. Yes, but be aware that this resolves the error by simply stripping out the asterisk. Which might be okay if the asterisk isn't an important part of the search phrase, but if you want to match pages according to the presence of the asterisk then you'll need to whitelist it.
  2. The sanitizer method intended for text that will be used as a selector value is $sanitizer->selectorValue(). See for example in Ryan's demo skyscrapers site. By default this sanitizer will filter out the asterisk, presumably because it's a character used within some selector operators. But it looks like if you whitelist it in the $options argument and it will be retained and the error is avoided because the value gets wrapped in quotes. $q = $sanitizer->selectorValue($input->get('q'), ['whitelist' => ['*']]);
  3. The settings are made on the module config page and that means they are only accessible to superusers. When putting pages at the bottom this is usually for "admin helper" purposes that a superuser would set up, but I would think that forcing pages to the top is more a content management function that needs to be manageable by non-superusers. It might be something that is better handled with a hook or just a Page Reference field. Can you describe the use case where you want pages kept at the top? Then I can consider it or suggest alternative ways of achieving it.
  4. Well if you are talking about writing your own SQL query that's fine and you're totally free to do that in PW. But your question related to the use of PageFinder selector strings, and I'm just trying to help you by explaining what values are valid for the "sort" keyword.
  5. When you sort by "something" this means that "something" is the property you are sorting on, and the sorting will occur either ascending or descending by the value of the property. In cases where your sorting involves a database query such as $page->find() then the property you are sorting on needs to be a column in the database that the ORDER BY can apply to. An example: if you have a field "fruit" then you can sort on it because it has an ascending or descending value in its database column: "apple, banana, cherry" or "wineberry, tangelo, strawberry". But you can't sort by "fruit=banana" because that isn't something that has a range of ascending or descending values and doesn't correspond to any single column in the database. I understand what you're trying to do but this isn't something that can be accomplished by a single sort property - you have to do more of the work yourself and use more than one selector, merging the results together. The Find Merge module might allow you to do this in a simple way: // Define selectors to merge results of // You could also define any secondary sorting for each selector as needed, e.g. sort=title $selectors = [ 'template=repeater_requests, help_roles=1', // These results will come first 'template=repeater_requests, help_roles!=1', // These will be added after to make up the limit if needed ]; // Get results // You can use "start" in the options argument if needed (see module readme) $results = $pages->findMerge($selectors, 20);
  6. Maybe this? https://processwire.com/blog/posts/processwire-core-updates-2.5.14/#multiple-templates-or-parents-for-users Just my two cents: based on forum topics and GitHub issues my impression is that people encounter troubles pursuing this strategy. I've always thought that leaving the user pages where they are by default and using URL segments for profile pages or similar is a much safer bet.
  7. Thanks Adrian, that's a really good idea! I think a single save button for the whole panel would be good because it might be useful having all the dumps that occurred together be connected in that way. Although having individual save buttons would be fine too - I think I'll find it very useful in either case. Edit: could the archived dumps be given a label when saving them? Like maybe a text input that gets populated with the current datetime by default but can be added to or overwritten before clicking the archive button?
  8. It took some investigating and it would be great to have this made more obvious in any documentation for $config->pagefileSecure... Behind the scenes pagefileSecure is using $files->send(): And $config->fileContentTypes forces download for certain extensions based on whether the content type is preceded by a + sign. You can override the default for the pdf extension in your /site/config.php and then the files should display in the browser: $config->fileContentTypes('pdf', 'application/pdf'); // No plus sign before the content type
  9. In v0.2.0 I've added a Pageimage::megapixelsDimensions() method that returns just the dimensions needed to resize an image to a target megapixel value. I used this recently to create a gallery of sponsor logos in normal and high dpi variations. Example from the updated readme: foreach($page->logos as $logo) { $dimensions = $logo->megapixelsDimensions(0.01); $width = $dimensions['width']; $height = $dimensions['height']; $width2x = $width * 2; $height2x = $height * 2; echo "<img src='{$logo->size($width, $height)->url}' srcset='{$logo->size($width, $height)->url} 1x, {$logo->size($width2x, $height2x)->url} 2x' alt='Logo' width='$width' height='$height'>"; } I've also added the module to the PW directory.
  10. A feature idea maybe for a rainy day... Sometimes I find I want to save a record of what is in the Dumps panel. I usually just copy/paste to a text document but it would be cool if there was a download button that saved the contents of the Dumps panel to an HTML file. That would be nicer because of the better formatting and expand/collapse features. Perhaps not so simple to do because I guess it would be best to embed any needed CSS and JS and the HTML file creation and download would need to happen via JS. So maybe not worth the trouble if it's a pretty niche need, but just thought I'd jot the idea down while it was fresh.
  11. You could just use ->parent twice: $parent = $page->parent; $grandparent = $parent->parent;
  12. @DrQuincy, you could use JavaScript to remove any disallowed characters from the input if the href is a tel link: $wire->addHookAfter('ProcessPageEditLink::execute', function(HookEvent $event) { $event->return .= <<<EOT <script> $(document).ready(function() { $(document).on('blur', '#link_page_url_input', function() { var href = $(this).val(); // If the href is a tel link if(href.startsWith('tel:')) { // Remove any disallowed characters href = href.replaceAll(' ', '').replaceAll('(', '').replaceAll(')', ''); $(this).val(href).trigger('change'); } }); }); </script> EOT; });
  13. Welcome @protro 🙂 What you have is fine. This is another way you could do it, which is perhaps a bit more readable: $items = new PageArray(); foreach($page->children as $child) { if($child->hasChildren) { $items->add($child->children); } else { $items->add($child); } } $items->sort('-date'); And if the objective happens to be "I want all the descendants that don't themselves have descendants" then this is potentially quite a bit more efficient because it's only a single DB query: $items = $page->find("children.count=0, sort=-date");
  14. @Guy Incognito, could you please reopen the GitHub issue because I think there is a bug that needs attention? I've added a comment to the issue.
  15. @Guy Incognito, as a general debugging tip: you should use a debugging tool like TracyDebugger rather than relying on message() because if some code somewhere does an exit() or die() then you might not see any visible message. For example, Session::redirect() calls exit(0) and maybe other core methods too. TracyDebugger has a Dumps Recorder panel that can capture any dumps that otherwise might get missed. And when you're troubleshooting and trying to narrow down an issue you don't want any non-essential code executing. In your example you have: public function upgrade($fromVersion,$toVersion) { $this->___install(); $this->wire()->message('Upgrade method called'); } But it would be better not to call ___install() before your debugging message because something might be happening in ___install() that prevents your message. So probably this would be a good way to check if the upgrade method is being called: public function ___upgrade($fromVersion, $toVersion) { bd($fromVersion, "fromVersion"); bd($toVersion, "toVersion"); } As for the problem itself, I tested here and can report: 1. The method name must be ___upgrade() and not upgrade(). The docs for Module make it sound like it is optional whether the method is made hookable with the underscore prefix but that seems to be incorrect because I can't see the method firing if the underscores are missing. So either that's a bug or the docs need to be updated. 2. The method is called when the module is next loaded, not necessarily when you do a Modules > Refresh. The core message gives a hint about this: If your module has autoload set to true then it will be loaded immediately after the refresh (and on every other page load). But if it's not autoload and you want to see the ___upgrade() method called then you can force the module to load like this: $modules->get('YourModuleName'); This isn't a bug as whatever actions you are taking in ___upgrade() will get applied in time for the next usage.
  16. Hi @Roope, There seems to be a problem when the text for an email link contains the smart apostrophe character: ’ It causes part of the closing <a> tag to get duplicated and this appears as visible text in the browser. Source code in CKEditor: After Email Obfuscation has processed it:
  17. I think perhaps you missed the point of my earlier post: When you use this approach you don't need a different URL to the regular one. If a non-logged-in visitor tries to view a page that you must be logged in to view then they get redirected to your custom login form and the ID of the page they tried to view is preserved in a GET variable (you could use a URL segment to hold the ID instead of a GET variable but I can't see a reason why that would be preferable). So let's say I try to view a restricted page at https://www.websitedomain.com/articles/i-love-processwire/ It doesn't matter how I got the URL - it could have been in an email, or a browser bookmark, or whatever. If I'm not logged in when I try to view it and the page template is configured like I showed in my earlier post then I'm automatically redirected to https://www.websitedomain.com/my-login-page/?return=1234 And if the hooks I showed are in ready.php then after I login I'm automatically returned to https://www.websitedomain.com/articles/i-love-processwire/
  18. @tires, if it's working for you then great, and I don't really get how URL segments relate to what you're doing, but what I was suggesting is to use hooks like this: // Add return GET variable to form action URL so it's available after the login form is submitted $wire->addHookAfter('LoginRegister::buildLoginForm', function(HookEvent $event) { /** @var InputfieldForm */ $form = $event->return; $return_id = (int) $event->wire()->input->get('return'); if($return_id) $form->action .= "?return=$return_id"; }); // If login is successful... $wire->addHookAfter('LoginRegister::loginSuccess', function(HookEvent $event) { $return_id = (int) $event->wire()->input->get('return'); // ...and there is a return page ID... if($return_id) { // ...check that the user can view the page and if so redirect back to it $return_page = $event->wire()->pages->get($return_id); if($return_page->id && $return_page->viewable()) { $event->wire()->session->location($return_page->url); } } });
  19. One more option... You could copy MarkupHTMLPurifier from /wire/modules/Markup/ to /site/modules/ and then select it as the copy you want to use. Then edit HTMLPurifier.standalone.php to replace this code with: return '<' . $token->name . ($attr ? ' ' : '') . $attr . '>'; Seems to solve the slash issue without affecting HTML5 elements like <figure>
  20. @tires, when redirecting to a login URL from a page that has restricted view access PW has a built-in option to include the ID as a GET variable. You can make use of this ID number in a hook after successful login to get the page that the user was trying to access and then redirect back to its URL.
  21. @patrick, try this: $wire->addHookAfter('MarkupHTMLPurifier::initConfig', function(HookEvent $event) { $settings = $event->arguments(0); $settings->set('HTML.Doctype', 'HTML 4.01 Transitional'); }); For this to take effect you'll also need to clear the HTML Purifier cache which you can do by executing the following once (the Tracy Debugger console is useful for this sort of thing): $purifier = new MarkupHTMLPurifier(); $purifier->clearCache();
  22. I updated my example because $input->is('post') is probably a bit too broad. It might be fine for your case but if you want to show the RuntimeOnly field value as a column in a Lister then $input->is('post') is true when the Lister results get AJAX-loaded according to the filter form values. So checking for the Page Edit submit button value with if(!$input->post('submit_save')) is probably better.
  23. Hmm, I guess the field is getting output formatting turned on during the save process and the page editor doesn't explicitly turn it off. I can think of a couple of ways around this. You could get the formatted value and output the markup only if the Page Edit form is not in the process of being submitted (as detected by "submit_save" button value not being present in $input->post): if(!$input->post('submit_save')) { $image = $page->getFormatted('your_image_field'); if($image) { // ... } } Or you could deliberately get the unformatted value which will be a Pageimages WireArray. $pageimages = $page->getUnformatted('your_image_field'); $image = $pageimages->first(); if($image) { //... }
  24. @mel47, this sanitizer method will work with any text - it doesn't matter where the text comes from. Use Tracy Debugger to check that the value you are supplying to the sanitizer method is definitely text and not something else.
  25. In the context of CKEditor the <br /> tag is probably caused by the CKEditor settings rather than HTML Purifier. Using this answer as a reference, you could put the following in /site/modules/InputfieldCKEditor/config.js: // When CKEditor instance ready CKEDITOR.on('instanceReady', function(event) { // Output self-closing tags the HTML5 way, like <br> event.editor.dataProcessor.writer.selfClosingEnd = '>'; });
  • Create New...