Jump to content


Popular Content

Showing content with the highest reputation since 09/26/2020 in all areas

  1. 23 points
    This week I’ve been working on updates for ProcessWire 3.0.168 as well as a new Stripe payments module for FormBuilder. In the core, the ProcessPageView module that handles all requests got a pretty significant refactoring. While it was largely focused on optimization, I also just like to go in every few years and rewrite stuff in high traffic modules like this to keep the module fresh, as well as keep my mind fresh on how it all works. I find there’s often room to do something better. The ProcessLogin module also got some upgrades this week that are primarily focused on maintaining the contents of a request URL in the admin between guest and admin user states. Now it can retain most query strings in a request URL after login. There’s still more to do in 3.0.168 so the version bump isn’t being made this week but may be ready next week. So far there are also a couple of GitHub issue resolutions and $sanitizer method improvements as well. On the FormBuilder side, we have the Stripe payments Inputfield, but since that module has been built, Stripe has released new APIs to handle SCA payments (soon required for EU transactions). With these types of payments, as I understand it, a multi-factor type process takes place where the user confirms the transaction with their credit provider. So it changes the payment flow quite a bit… enough that I’ve found the current Stripe payments module can’t really be adapted for it, at least not in a reliable way. That’s because the new API requires that the payment take place interactively before the form is submitted, since the user has to manually confirm it outside the form. So this will inevitably lead to cases where a payment has been charged but the final form isn’t submitted for one reason or another. Maybe it would work most of the time, but it just doesn’t seem like a reliable transaction flow to me. For this reason, I’m building a separate module for FormBuilder that provides a better alternative for the SCA transactions. With this module, the user submits the form, but FormBuilder saves it as a partial/pending form submission. Following form submission, the user goes through the SCA payment process with Stripe. When that completes, Stripe sends a webhook to FormBuilder that converts the form submission from pending to completed, at which point emails are sent, FormBuilder actions executed, etc. So it's Stripe that submits the final form, rather than the user. I’ve got a lot of work still to do here, but since a few people have contacted me looking for SCA support with Stripe payments, I just wanted to keep you up to date and let you know it’s in progress. The existing InputfieldFormBuilderStripe module will of course continue to be developed as well, as most regions outside the EU do not require SCA. Thanks for reading and have a great weekend!
  2. 22 points
    ProcessWire 3.0.168 contains 16 commits relative to 3.0.167 and is focused largely on minor issue fixes and improvements, with 8 reported issues fixed and 8 improvements. This week the larger focus was on the ProcessWire modules site. I finally got some serious work done with that this week, and am building good momentum. The front-end of the modules site is being moved into the main ProcessWire site, though the back-end will remain an independent ProcessWire installation. The main ProcessWire site uses multi-instance support to boot the modules site whenever it needs to pull or update data from it. Here's a simplified example: $site = new ProcessWire("/htdocs/modules.processwire.com/"); $items = $site->pages->find("template=module, sort=-created, limit=10"); echo $items->each("<li><a href='/module/{name}/'>{title}</a></li>"); The nice thing is that I’m finding performance to be excellent here, about the same as if I weren’t booting multiple ProcessWire installations. I’m sure there’s some overhead if measured, but it sure isn’t felt. One thing I did learn is that when it comes to pagination, if you want your separately booted site to be aware of the current site’s pagination, you need to tell it the page number. Otherwise the bit of code above will always return the first 10 modules, regardless of pagination number. It seems obvious now, but it took me a minute to realize why. So if pagination is being supported, you'd add this before the $site->pages->find(...) in the example above: $site->input->setPageNum($input->pageNum); For front-end work like this, it's also a good idea to tell your booted site if you want output formatting enabled, so that page titles and such come out entity encoded, for example: $site->pages->setOutputFormatting(true); ...or if you prefer the shorter alias: $site->pages->of(true); One big difference with the new modules directory is on the management side for module authors. This part is powered by LoginRegisterPro so that now you have an account to manage all of your modules within. Further, you have the option of maintaining your module author public profile and protecting your account with PW’s two-factor authentication. That's just for starters. All of this is in the early stages of development, but if the development schedule remains as planned, I’ll be following up with more info over the coming weeks, in addition to the regular core and module updates. Have a great weekend!
  3. 21 points
    Last week I told you how I was working on a getting a new Stripe payment method working with FormBuilder… and I’m still working on it. That wasn’t exactly the plan. Stripe isn’t quite as easy to work with as it used to be, or maybe Stripe thinks I’m not as easy to work with as before. Either way, I’m learning, and it’s been a good opportunity to expand FormBuilder with its own class for plugin “action” modules. Hopefully some of this work on the Stripe side can apply for other payment methods, or any type of action you’d want to take with a form submission. It’s probably going to take another week or so before this module is ready to release in the FormBuilder board, but it’s going to be built well and accompany a new version of FormBuilder too (that supports these plugin actions by way of PW modules). Having these actions as ProcessWire modules opens up new doors for FormBuilder, and I may even move some of the built-in actions (like saving to Google Sheets) into this type of module, which would be nice for hooks and maintainability. There’s not a lot to report on the core side this week. There are a few commits and improvements, but not yet enough where I’m ready to bump the version to 3.0.168. One small but useful improvement is that handling of selector queries for words with apostrophes has been improved. One of my clients noticed they were having trouble with their site search engine matching terms like “Alpe d’Huez” and “L’estello”, and so our page finding engine has been improved to narrow them down with the fulltext engine and then find the exact matches with regular expression queries. This improvement enhances most of the partial text matching operators. It also solves the issue of there being different kinds of apostrophes (ascii straight vs utf-8 curly), among other things. Overall the core is running running very smoothly on the dev branch, so I’m thinking we may try and do another merge to master before 3.0.170. Thanks for reading and have a great weekend!
  4. 13 points
    ProcessWire 3.0.167 is the newest version on the dev branch and contains the updates mentioned last week, as well as the following: Improvements and optimizations to several database fulltext index-based text-searching operators (such as *=, ~=, *+=, ~+=) so that they can better match words too short to index, as well as many stopwords. (code changes) New $input->queryStringClean() method is like the existing $input->queryString() method except that it enables you to get a cleaned up version according to rules you specify in an $options argument. I added this method primarily because it’s something I need in the core for some planned updates. But it’s in the public API because I thought it might be useful for some other cases as well. Kind of technical, but some minor improvements to the $sanitizer array methods were made so that they can now support associative arrays with a ‘keySanitizer’ option that lets you specify which sanitizer method to clean up array indexes/keys. The $sanitizer->validateFile() method was rewritten and improved plus new ‘dryrun’ and ‘getArray’ options were added. The core file and image fields have been updated with the ability to require (rather than just utilize) a FileValidatorModule for certain file upload extensions. This was motivated by SVG files being increasingly problematic (or at least my understanding of them) because they can contain the kind of bad stuff that regular markup can (scripts, loading external assets, etc.). But since SVG files are used by many just like the bitmap image formats (JPG, GIF, PNG, etc.) exploits can spread quite easily and unknowingly. I’m not aware of that ever occurring in a ProcessWire site, but it’s one of those things that strikes me as being an inevitable problem for any website (on any software) that has regular SVG uploads. ProcessWire doesn’t allow SVG file uploads by default, but you can manually add “SVG” to your allowed upload extensions for any file/image field… and from what I understand now, a lot of people are doing this—using SVG files not just during development, but as an image format that their clients upload too. The usual protections of having a trusted user admin environment don’t help much here. That’s because what matters is not whether the uploading user is trusted or not, but whether the source of the SVG is trusted. And that’s something we have no control over. It seems apparent the core could provide some extra help and guidance in this area. So ProcessWire now requires you install the FileValidatorSvgSanitizer module if you want to have SVG uploads, OR you can check a box in the file/image field settings to whitelist the extension (acknowledging you understand the risks). Now you could manually add HTML or JS as allowed upload extensions to a files field as well— and if you are rendering the resulting HTML markup or JS directly in the code of your website, then the same risks would be present as with SVG. But the risks seem obvious for doing this with HTML or JS files. Plus, why would someone do that with HTML or JS files unless for some very specific development purpose? I think it’s unlikely any of us are running websites where clients might be downloading HTML or JS files from other sources and uploading them into the website. And even further unlikely that we’d written the site’s code to include the contents of those files among the site's markup. Whereas, this is essentially what happens with SVG files, from what I understand. As I’ve come to learn this week, it’s even quite common to do this (maybe I’m late to the party). Given the above, this week I rebuilt the existing FileValidatorSvgSanitizer module from the ground up, so that it now uses a better/newer SVG sanitization library found by Adrian. I’d suggest installing the module if you are supporting SVG uploads in your site. It seems to do a nice job of cleaning the harmful stuff out of SVG files. I’m not aware of anything it can miss, but I’d still advise some caution with SVG file uploads even if you have the module installed. If you currently allow SVG file uploads but don’t really need them, just remove SVG as an upload option, as that’s still the safest bet. That’s essentially what the current dev branch version does: if you’ve added SVG as an allowed upload extension, it’ll disable it until you decide if you need it; and if you do, then install the sanitizer module or whitelist the extension. I know not everyone is going to like that, but it seems like it’s the right and safe thing to do; as well as a good strategy going forward for any other file formats with similar concerns. When our next master version arrives, it’ll be in the upgrade instructions as well. The core has been updated so that it can support the same means for any other file formats we come across in the future that might be problematic in similar ways. That’s everything I can remember that’s new to 3.0.167. Thanks for reading and have a great weekend!
  5. 12 points
    Format Datetime fields as Carbon instances. You can find the latest release and the complete readme on Github. Installation composer require daun/datetime-carbon-format Usage All Datetime fields will now be formatted as Carbon instances instead of strings. Some examples: // $page->date is a Datetime field // Output format: j/n/Y echo $page->date; // 20/10/2020 echo $page->date->add('7 days'); // 27/10/2020 echo $page->date->format('l, F j'); // Monday, October 20 echo $page->date->year; // 2020 echo $page->date->diffForHumans(); // 28 minutes ago Frontend only The ProcessWire admin seems to expect datetime fields to be strings. This module will only return Carbon instances on frontend page views. Date output format When casting a Carbon instance to a string (usually when outputting the field in a template), the field's date output format will be respected. Links GitHub • Readme • Carbon docs PS. I remember reading about a Carbon module in a recent newsletter, but couldn't find it anywhere. Was that you, @bernhard?
  6. 10 points
    BayTech360 is a System Integrations Specialist serving the US out of San Francisco. They wanted to revamp their website and asked Pigtail Pundits to help with it. The new website is built to storytelling standards of StoryBrand and other direct response advertising frameworks. This site features, sell-focussed copy which is our trademark. This is mapped to an elegant, clean design. Built atop ProcessWire, our favourite CMS, with ProCache for speed. Check it out at: https://www.baytech360.com/
  7. 9 points
    This week a second new module for processing Stripe payments has been added to FormBuilder. Unlike our other Stripe Inputfield for FormBuilder, this new one uses Stripe Checkout and supports 3D Secure (SCA) payments. We’ll take a closer look at it in this blog post, plus we’ve got a live demo of it here too— https://processwire.com/blog/posts/stripe-payment-processor-form-builder/
  8. 7 points
    Agrio is a medium-sized publisher with more than 70 employees and offers a leading cross-media agricultural portfolio. In the more than 30 years that Agrio has existed, we have managed to gain the position of market leader, with the highest reach in the agricultural in the Netherlands. In addition, our customers know where to find us for various printing, web design, copywriting, video productions and graphic design. Agrio does all this with a lot of passion and a proactive attitude. Farmer sobriety predominates. Independence, job satisfaction and growth are important core values within the organization. There is always room for new talent. We currently have room for a PHP Developer in our Media and Design department. https://www.agrio.nl/vacatures/php-developer/
  9. 7 points
    I found this random picture generator the other day but kept forgetting to post it here. It's basically lorem ipsum but for photos. They have quite a nice feature set too.
  10. 7 points
    There are a few problems with that code: Switching $magazine to $page doesn't actually help at all. $page is not defined here either. As I mentioned in my previous post, you're in function context, and in that context you only have access to a) function arguments ($event), b) variables you've made accessible with "use" (currently there are none), and c) global functions. $page is none of those. Another issue is that there's no savedPageOrField method for Inputfield, so Inputfield(...)::savedPageOrField is never triggered — what you're looking for is Pages::savedPageOrField. From your post I assume that you've put this code in the template file, i.e. /site/templates/your_template_name.php? If so, the hook only applies to when you're viewing a page using that template, i.e. it has no effect in Admin. I'm not sure if that's what you really intended, but I'd assume not — more likely you'd want to put this hook somewhere it gets added in the admin as well, so perhaps /site/init.php or /site/ready.php. ... and, finally, even if your code did work, you would've likely ran into an infinite loop: if you hook into page save and save the page, that'll trigger the page save hook, which will then save the page and trigger the page save hook again, which... you know the drill. Pages::saveReady() is often better method to hook, as you can just modify the page values, and they'll get saved soon after (you don't have to call save in your hook) 🙂 In this case something along these lines could work: // hook into Pages::saveReady $wire->addHookafter('Pages::saveReady', function($event) { // get current Page object — in this case this is the first argument for the $event object $page = $event->arguments[0]; // bail out early if current Page *doesn't* have the field we're interested in if (!$page->template->hasField('snipcart_item_image')) return; // ... and also bail out early if the snipcart_item_image field hasn't changed if (!$page->isChanged('snipcart_item_image')) return; // now that we know that snipcart_item_image has changed, set a custom value to another field $page->set('imagecolorat', 'YOUR_NEW_VALUE_HERE'); // finally, populate our modified $page object back to the event $event->arguments(0, $page); }); Note: written in browser and not properly tested.
  11. 7 points
    This is a bit of a border case on this forum, I know — but it's also such a great event that I wanted to share it anyway: https://wpaccessibilityday.org/. In short this is a currently ongoing 24 hour streaming video / webinar event with loads and loads of accessibility focused talks. I'm writing this right after the first talk, so you haven't missed much if you jump in now (and again, it's a 24 hour event, so there's a lot more to come). Direct link to the stream: https://www.youtube.com/watch?v=X0BcKR2Go1E. Some of the talks are obviously pretty WP centric, but based on the schedule I'd say that the majority of the content should apply to just about all regular websites, as well as content management platforms in general 🙂
  12. 6 points
    After 9 years using ProcessWire I still do multiple times a day a typo writing template as tempalte (probably write it wrong more often than right). I know few of my co-workers does the same. Is this curse for us Finnish people, or is tempalte thing in other parts of the world also?
  13. 6 points
    Yeah, we all struggle with that sometimes. 🙂 I did a bit of experimenting and here's another way the language options can be removed from the title field: // Single-language title field for "test-template" at Page Add $wire->addHookAfter('ProcessPageAdd::getAllowedTemplates', function(HookEvent $event) { $tpls = $event->return; $t = $event->wire()->templates->get('test-template'); if(isset($tpls[$t->id])) $tpls[$t->id]->noLang = 1; $event->return = $tpls; }); // Single-language title field for "test-template" at Page Edit $wire->addHookAfter('ProcessPageEdit::buildFormContent', function(HookEvent $event) { /** @var InputfieldForm $form */ $form = $event->return; $page = $event->object->getPage(); if($page->template == 'test-template') { $title = $form->getChildByName('title'); if($title) $title->useLanguages = false; } });
  14. 6 points
    It was Kongondo doing maintenance release to old one. But I know Kongondo is working hard to get v2 released.
  15. 6 points
    Hey folks! Just wanted to mention that ProcessRedirects 2.0.0 is now out. As far as I can tell it should fix most of the issues that have been reported here, as well as those reported via GitHub. This is a major update and the module now requires ProcessWire 3.0.112+ and PHP 7.1+, so please keep that in mind if and when updating 🙂 Here's a kind-of-a-changelog for this release from the PR that got merged earlier today: In case anyone is wondering why update this module now even though we already have a very powerful alternative (Jumplinks), the thing is that this module still serves a purpose: it's super easy to use, and does what it needs to do — no more, no less. Powerful features can be a double-edged sword, as they also tend to increase complexity, at least to some extent. When it comes to "power users", Jumplinks is by far a superior tool, but for regular content editors who just need the occasional shortlink (or something similar), this module is often just the right fit. Hope that makes sense. Anyway, I still have some relatively minor additions in mind that I'd like to add to the module (assuming that Antti thinks they are a good fit), but again, for the most part this module already does what it needs to. Power users will likely feel more at home with Jumplinks 🙂 If you find a bug or have a feature in mind that this module really needs to have, feel free to open an issue at the GitHub repository. Thanks!
  16. 5 points
    Does anybody else feel like the login screen could use a revamp? While it might not be the most important thing in the world, first impressions count. On large(r) screens the login form seems to get lost in the upper third. The rest of the admin looks a lot cleaner and more deliberate. A few tweaks would go a long way in making the login screen work on all device sizes. Those are two custom styles I've been adding to my sites lately, one PW-branded and one not. No markup changes needed, just CSS. This second one borrows heavily from Twill's login screen. The floating environment label has turned out to be really useful to see at a glance if one is editing on staging or live. Not sure if there's a way to make this 100% core compatible.
  17. 5 points
    Here's a hook (add to /site/ready.php) that allows you to set a description and your own help notes for each checkbox in the Status field: // Add some extra notes to the options in the Status field of Page Edit $wire->addHookAfter('ProcessPageEdit::buildFormSettings', function(HookEvent $event) { /** @var InputfieldWrapper $form */ $form = $event->return; $status = $form->getChildByName('status'); if(!$status) return; // Add a description to the field if you like $status->description = 'You can apply various statuses to this page to control its visibility and editability.'; $options = $status->options; // Define your notes here $notes = [ 2048 => 'Peter Piper picked a peck of pickled peppers.', // Unpublished 1024 => 'How much wood would a woodchuck chuck, if a woodchuck could chuck wood?', // Hidden 4 => 'She sells sea shells by the seashore.', // Locked ]; foreach($options as $key => $value) { if(!isset($notes[$key])) continue; $options[$key] .= "[br]{$notes[$key]}[br]&nbsp;"; } $status->options = $options; });
  18. 5 points
    No issue with "tempalte" but if if ever remember how to write "width" I'm sure I'll pokevolve into a 10x engineer haha.
  19. 5 points
    @The G Your wish is my command 😅 I just added another config option for an alternative banner template file! In addition (to be even more flexible 😄 ) I included your idea of the hookable methods for banner template and js file. /** * checks for a alternate banner template path * @return string the path of the banner template file **/ public function ___getBannerTemplateFile() { return (!empty($this->alternate_banner_template) && file_exists($this->wire('config')->paths->root . $this->alternate_banner_template)) ? $this->wire('config')->paths->root . $this->alternate_banner_template : $this->wire('config')->paths->$this . 'PrivacyWireBanner.php'; } So now you have to decide whether you prefer to hook or configurate 😄 --> 0.3.3 <--
  20. 5 points
    Since I first rebuilt this site in Processwire, it's had a major overhaul, with all competition data now handled on the site rather than in a separate desktop database app. Members are able to access the admin, but using AdminRestrictBranch, some hooks in ready.php and some custom process modules, logged in users are taken to a dashboard that varies depending on their role, so members can only see their own competition images (in a list via Lister Pro) and submit more, while the competition administrator has a dashboard that allows them to manage all aspects of competitions. Competitions close off automatically once their closing date has passed. CustomUploadNames module is used to automatically rename image files when they are uploaded so that once competition entries are downloaded as a zip file, they can be identified by filename. On the front-end slideshows are generated automatically once competition results have been entered, which is done via Lister Pro.
  21. 5 points
    I added a feature for this in todays 0.3.0 (not pushed the release tag yet, as there was a lot of rewriting to implement this feature). If you want to show an opt-in element instead of the consent-required element, just add a data-attribute data-ask-consent="1". Here is an example: <iframe src="" data-src="https://www.example.com/" data-category="marketing" data-ask-consent="1" frameborder="0" height="400" width="400"></iframe> In this case, the iframe gets only loaded, when cookies of type "marketing" are allowed. If not, the user will be asked for consent. The text of the consent-window is configurable in the module config. The markup of this message also includes an css class with the type of cookie, if you want to style them specifically. privacywire-ask-consent.mp4
  22. 5 points
    Well, you can still create a page in your source PW installation that outputs either a JSON of your n latest articles, or complete with markup. On the other PW installation, just fetch that page in some way and include it in your template file, which can be as easy as file_get_contents('http://pw-site-with-articles.com.test/latest-articles.php'); No need to install and configure a full-fledged REST API module for that.
  23. 5 points
    Important update: I've just updated to module to version 2.0.0 which fixes the issues with the API requests and makes the module work correctly again. However, the module now requires ProcessWire 3.0.167 or above! Read on below for an explanation. Since publishing this module, I ran into several problems with API requests not working correctly. I found that the reason was both an issue with the way the module formats it's API requests, as well as some issues with ProcessWire's cURL implementation, which means that some requests wouldn't work correctly (namely PUT and DELETE requests). I then submitted a pull request to the ProcessWire core which fixes those issues, which were thankfully accepted by ryan. The fixes are now live and available in ProcessWire 3.0.167, and I've updated the TrelloWire module to fix some internal issues as well, so the module should now work correctly once again. Unfortunately, this means that ProcessWire versions below 3.0.167 won't work correctly. New options: Switch the network implementation used by the module There's a new configuration option available that you can use to force the module to use cURL, fopen or socket connections respectively. Check out the documentation for usage information! If you can't update to 3.0.167 ... You can still install and use the module on older ProcessWire versions (though the installation will ask for confirmation if you are below 3.0.167). The module will try to use fopen to connect to the API on any ProcessWire installation below 3.0.167, but I can't promise it will work correctly. You can also try socket connections using the configuration option above, but I couldn't get it to work in my test environment. Let me know if you need support or something isn't working for you! @maddmac Just tagging you to let you know you don't need to use the dev branch from Github anymore 🙂
  24. 4 points
    Hey @teppo, thanks for your input - sounds good! I just added the project to packagist and activated the webhook for auto updating: https://packagist.org/packages/blauequelle/privacywire
  25. 4 points
    @ngrmm That actually was my first type of implementation (separating css and js), but as the CSS file would be very small (554 Byte), it actually is slower to load these two connections vs. loading only one JS file with the CSS included ( even with HTTP/2 - I tested it alot!). This is the total amount of styles used by PrivacyWire (beautified for better readability): .privacywire { position: fixed; bottom: -250%; left: 0; right: 0; box-shadow: 0 -1px 3px rgba(0, 0, 0, .3); opacity: 0; background: #fff; z-index: 1; padding: 1rem; transition: bottom .3s ease-in, opacity 1s ease-out } .privacywire .privacywire-header { font-weight: 700 } .show-banner .privacywire.privacywire-banner, .show-message .privacywire.privacywire-message, .show-options .privacywire.privacywire-options { bottom: 0; opacity: 1; transition: bottom .3s ease, opacity .3s ease } .privacywire button[hidden], [data-ask-consent-rendered="1"], div.privacywire-ask-consent-blueprint { display: none } You could do the following: 1. Uncheck the config checkbox "Add basic CSS Styling": 2. Add the styles to your own stylesheet.
  26. 4 points
    I fixed these two topics in 0.3.2. @snck: There really was a bug with the "Accept all" Button - thanks for noticing! @ngrmm: You can choose now in the module config which header tag you want 😉 For keeping backwards compatibility, the default value still is <header>.
  27. 4 points
    v0.3.2 released. This version reverts to the hook methods used in v0.2.3 and earlier of this module now that the core circular reference issue was fixed in PW v3.0.166. To upgrade to v0.3.2 you must be running PW v3.0.166 or newer, which is currently only available on the dev branch.
  28. 4 points
    Those numbers seem pretty normal. Just for comparison: The doc (HTML) part of a fairly complex site I recently finished takes ~600-900ms when I'm bypassing ProCache. This is from browser, though, so could be a bit different from what you're measuring (not sure how exactly you got these numbers). With ProCache I'm getting consistent < 100ms. ProCache serves content directly from disk (via Apache), bypassing PHP and database, so it's naturally quite a bit faster. Took a cursory glance at a couple of (also relatively complex) WordPress site that I know for a fact are well built and hosted on pretty powerful hardware, and load times for these were somewhere between ~1.5-3 seconds uncached, 200-400ms cached (static cache using nginx, I believe). In my opinion 1-3 seconds would still be "pretty good" for just about any ProcessWire or WordPress site without proper caching. Anything below 4-5 seconds is in the "pretty normal" range, while 5-10 seconds is just plain wrong (but sadly not that rare). 5+ seconds is usually a sign of really bad hosting, or really bad implementation 🙂 Might be worth noting that, in my experience at least, PHP is rarely the real bottleneck: if the server returns the markup in a few hundred milliseconds but then there's blocking JavaScript, CSS, or perhaps a large image that takes hundreds of milliseconds to seconds at worst to finish loading and/or executing, it would be better to focus on that. Just saying; developers (including yours truly) have a tendency to focus way too much on shaving milliseconds off one end, even if at the other end it might be possible to shave off seconds 😛 Template cache loads the page from the disk and doesn't execute any of your markup generating code, but it still has to go through ProcessWire, so there's definitely some overhead there compared to ProCache. How beneficial template cache is (in comparison to non-cached site) depends a lot on how complex the site is and how well it's already optimized. Kind of covered this already, but to reiterate: it would definitely make a difference. ProCache is usually low maintenance, but this depends a bit on how your content is generated — such as whether it's all from stored with/in ProcessWire, or if you have parts that are loaded (especially with PHP) from other sources. Typically ProCache gets flushed based on predefined rules when pages are saved, so if your content isn't stored on pages, that could be a potential issue. In which case you may even need to programmatically flush it (via cron or some other method). You can configure the preferred lifespan, so technically you can make ProCache stick to cached data almost indefinitely, and thus ProcessWire/ProCache will very rarely need to regenerate it. Though, again, in my opinion this is something that folks tend to pay too much attention to: if your typical page render (non-cached) takes 1-3 seconds at most and your cache hit ratio is 99+%, cache warming has so little actual effect that it's (in my opinion) mostly just wasted time and effort 🙂
  29. 4 points
    @ngrmm Yes, you can set regular cookies as mentioned in my first paragraph, though they won't be accessible through ProcessWire's $session API. But why would you load 87kB of library bloat for something that you can do in one line? 🙂
  30. 4 points
    Today there are two updates for PrivacyWire (newest Version V0.2.7 ) 1. The update of elements after giving consent now observs more attributes (also srcset for responsive images and width/height attributes - especially good for iFrames) 2. When the user wants to choose the detailled cookies, there is now a option to show another "Accept All" Button instead of the "Toggle" Button - configurable via module config.
  31. 4 points
    Thanks @wbmnfktr for noticing this! There really was a bug with the version number and async loading of scripts etc. I fixed this in V0.2.5. After changing the version number in the backend (and refreshing ProCache - especially when you have activated the option to minify local Javascript) PrivacyWire will check the version number first before handling the elements requiring consent.
  32. 4 points
    Yeah nice resource, I've been using them for a while, I guess they rebranded a while from unsplash.it 🙂 By the way, the pictures are from unsplash.com, so they are completely free and can even be used in final commercial products. Though they don't have many upload guards in place to prevent people uploading copyrighted material, so it's worth it to do a reverse image search just to make sure. There's also undraw.co for illustrations, which is nice because the illustrations are SVG files and you can customize the main color right on the website.
  33. 4 points
    If you really need some serious speed increase you can of course go directly to the database instead of using $pages. Though that is a lot more work, because you'll have to manually add status flags to your query, manage multilanguage support etc. I've done this for my module Automatically link page titles, the list of linkable titles and corresponding page IDs is retrieved directly from the field_title table. See the source code for reference. If you can't optimize the query, caching might be a solution, this way only the initial access will run slowly, but subsequent requests and queries will be fast. Your query varies by $item, $eventDate and $limit, so you could create a cache key based on that and store the results through the $cache API. Something like this: $limit = $item->qty; $cacheKey = implode('-', ['bookings', $item, $eventDate, $limit]); $cache = $this->wire('cache'); $selector = "template=booking, booking_items.booking_item.id=$item, booking_date=$eventDate, booking_status!=pending|cancelled, limit=$limit"; $pp = $this->wire()->pages; $otherBookings = $cache->get( $cacheKey, WireCache::expireSave, function () use ($pp, $selector) { return $pp->find($selector); } ) Quick and untested, might need some adjustments. You can use WireCache::expireSave to invalidate the cached results whenever any page is saved, though that's not very efficient if the bookings are edited very frequently. Or use a max age of a day or so, at the risk of sometimes showing outdated results.
  34. 4 points
    Not true, actually. You can: See these lines, here and here: $str = sprintf($this->_('%1$s %2$d of %3$d'), $label, $pageNum, $totalPages); // Page quantity, i.e. Page 1 of 3 $str = sprintf($this->_('%1$s %2$d to %3$d of %4$d'), $label, $start, $end, $total); // Pagination item quantity, i.e. Items 1 to 10 of 50 Here's how to do it 🙂 Setup -> Languages -> Your Language Find Files To Translate Look for \core\PaginatedArray.php under Translatable files in /wire/ Select #3 Click Submit Translate!
  35. 4 points
    I'm not surprised that 1000 repeater items in a field is slow to load. My suggestion is to replace your repeater field with child pages.
  36. 4 points
    Version Update 2.0.1 The current version has got a bug fix. Thanks to @ngrmm I could discover a bug which causes that the module cannot be loaded if the MatrixRepeater field ends with the name "repeater". The code was adjusted and information about the problem was provided. All information and downloads are updated in the first post.
  37. 3 points
    How does everybody feel about creating a separate language pack for official and/or popular modules which would usually be in the site folder? I just noticed the Norwegian language pack making that switch. Especially for the Pro modules (Lister, FormBuilder) it would be nice to have a drop-in solution. And if you don't need them, just install the core language pack and everything stays the same. As far as I can tell, the current de-DE language pack doesn't include module translations, right? I'd be willing to create a repo and get things rolling.
  38. 3 points
    @ngrmm I had a similar issue and went kind of a different route and added role="main" to my main header and excluded it later on in my PrivacyWire CSS. header:not([role=main]) { // here you go } For the moment that should work out quiet nice without any or at least only minor issues - at least when you are working with less, sass, SCSS and similar.
  39. 3 points
    @alexmercenary Thanks, glad that you are liking this module (saw your post in the FormBuilder board too). Makes my day actually, thank you. This is a module that I thought was necessary to build before December, when SCA in Europe will apparently be a requirement. I wasn't able to find a way that the existing Stripe Inputfield could be updated to support 3D Secure, at least not in a way that would be reliable with the form workflow. Basically, with 3D Secure, the charge takes place at the time the user inputs the card and an independent popup verifies it. So if the card collection is part of another form (as the Stripe Inputfield is), and someone pays but never submits the form (or submits but never fixes validation errors), you end up with an orphan charge. Stripe's solution to this scenario is that you should issue a refund. I thought that was too much for people to keep track of (charges that are missing a form submission). So thought it was necessary to build this module and include it with FormBuilder, especially for any of those in Europe that might already be using the Stripe Inputfield.
  40. 3 points
    Unless I want to save the value of a page object's property in the database, I would not change a page object's property because it is reasonable to expect that a property corresponds to a value in the database. If I change the property but do not save it to the database, then from that point on it is "confusing" to keep track of the actual value of the property as its value is no longer "in sync" with the database (as long as we are talking about the same request being executed, of course). To tell the truth, I do not really get what you are trying to solve. I was just trying to point out a few things that might – but not necessarily – cause issues.
  41. 3 points
    I think ProCache will always bring benefits as it basically turns the website into a static website, routing requests directly to html files. It will always have the bottleneck of the first request after the cache expire, so there's that (unless you do some work around it with cron for example). But as long as you configure your cache to expire correctly after page updates, there shouldn't be much trouble if your site is brochureware.
  42. 3 points
    $markup = array( 'item_content' => "<div class='InputfieldContent {class}'>{out}{error}{description}{notes}</div>", );
  43. 3 points
    Users are not typical pages, so you should use wire()->users->find() instead. Or, alternatively, you can use wire()->pages->find('template=user, id=..., check_access=0').
  44. 3 points
    I know you mentioned docs being confusing, but I'd still suggest taking another look at them — specifically this part, as it explains this pretty clearly: https://processwire.com/docs/modules/hooks/#defining-hooks. To simplify things a bit... the key difference between the first two is that $wire->addHookAfter() works outside classes, while $this->addHookAfter() is how you'd usually attach the hook when you're in a method of a class (i.e. while you're working on a module of your own). $page->addHookAfter() attaches the hook to the current Page object (which $page typically refers to), not all Page objects in general. Important distinction in case you're working with multiple pages and don't want your hook to run for all of them. Not sure if that explains it any better than the docs, but again the biggest difference is just the context in which you're defining the hook (use $wire when in template files, /site/init.php, /site/ready.php, /site/admin.php, etc. and $this when you're within a method in a class) and whether you want your hook to apply to a single object ($page, $pages, or a specific item such as $mypage where $mypage = $pages->get('some_selector')) or all items of a specific type. Most commonly you'll need your own hookable methods when you're, say, developing a reusable module. Instead of tweaking the module on a per-site basis, you'll likely want to keep it as-is and rather make some minor modifications by hooking into it's methods. This way you can easily update the module without having to redo or work around your modifications every single time. On some edge cases you might have a utility function on the site, and then depending on some other event you may want to say that "at this specific instance the method should do something else", so you'd want to make it hookable. Can't think of many cases where that'd make sense, though. I'm not sure what you're getting at here. Is this is just an example of what you're doing at the moment? Either way your hook looks fine to me. Should've read this more carefully. You're accessing $magazine object here, but if this is your entire code, that won't work — you're not defining $magazine variable anywhere. Since you're in function scope, you only have access to the arguments passed to that function, variables you've passed in with "use" language construct, and global functions. Even if $magazine exists outside your function, you'd have to pass it in with function($event) use ($magazine) { ... } That being said, what you're probably looking for is something like Pages::savedPageOrField(). If you take a look at that docs page, there are code examples dealing with changes etc. Or, alternatively, Pages::savePageOrFieldReady(), which occurs right before the page/field is saved (which means that you can modify the values right before they are saved to the database). ... and please let me know if I missed your point here 🙂
  45. 3 points
    Haha great, and sorry - I completely forgot the issue due some spontaneous new ProcessWire side project for the guest registration in Vienna/Lower Austria: https://www.heute.at/s/cowirtat-hilft-bei-der-registrierung-im-gasthaus-100106087
  46. 3 points
    The _x function is part of ProcessWire's translation system – using it is good practice, because it allows you to change hard-coded strings (such as the language code) through the backend without touching the code, and translate them to multiple languages for multi-language sites. You're probably just missing a translation. Go to Setup -> Languages -> Portugese (might also be default depending on your language setup), then under "Site Translation Files" check if the main.php is already listed, otherwise select it through "Find files to translate". Add the correct language code there and it should appear in your HTML!
  47. 3 points
    I might be misunderstanding something (I don't normally work on multi-language sites), but isn't it optional to enter page titles in any language other than the default? The user isn't forced to add a title in all enabled languages as far as I can see. So it seems like it's a question of user education more than anything else, the lesson being "only create page titles in languages that you need", which is really part of a more basic general lesson that any CMS user must learn: "only fill out fields that you have information for".
  48. 3 points
    Ok, you are right @Robin S. I think, now i understand you. 🤦‍♂️ Your idea to use a field for the parent-child relationship works great: I add a empty repeaterfield to template. In ready.php i add to a edit button (each children page) include pagination. It looks like it´s a repeater field items (old page situation). All happy. $this->addHookAfter('Inputfield::render', function (HookEvent $event) { $field = $event->object; $form = wire('modules')->get("InputfieldForm"); //get edit page $page_id = $this->input->get('id'); $page = $this->pages->get($page_id); //add child pages to empty repeater - items not moveable, deletable or to clone if ($field->name === 'products') { $childPages = $page->children('limit=15'); $pagination = $childPages->renderPager(['getVars' => array("id" => $page_id)]); foreach ($childPages as $childPage) { //build the fake-repeater header $wrap = $this->wire('modules')->get('InputfieldFieldset'); $wrap->addClass('InputfieldRepeaterItem InputfieldStateCollapsed InputfieldRepeaterMinItem InputfieldNoFocus'); $wrap->name = "repeater_item_{$childPage->id}"; $wrap->label = $childPage->index + 1 . ': ' . $childPage->product_title . ' Art.: ' . $childPage->title; //if all fields are filled out mark the header $isFilledOut = ($childPage->product_keyword && $childPage->product_type); ($isFilledOut ? $wrap->addClass("text-black", "headerClass") : ""); //add the edit button for the child page (class pw-modal for modal edit) $submit = wire('modules')->get("InputfieldButton"); $submit->attr("value", "Produkt Details bearbeiten"); $submit->attr('data-href', wire('config')->urls->admin . "page/edit/?id=" . $childPage->id); $submit->addClass('pw-modal uk-margin-bottom uk-margin-left'); $wrap->add($submit); $form->add($wrap); } $field_style = '<style>.text-black{color:black !important;}.InputfieldRepeaterItemControls{display:none !important;}</style>'; $event->return = $form->render(); $event->return .= $field_style; $event->return .= $pagination; } });
  49. 3 points
    The config option for this duration is now included in 0.2.3 😉
  50. 3 points
    I played around with multi-instances and found out that we currently (PW 3.0.163) are not able to use multiple instances when more then one site has set $config->useFunctionsAPI (in site/config.php) to true! Then I saw that, (when $config->useFunctionsAPI was set to false) in all instances $config->version returned the same version, that from the master instance. So, first I was a bit confused, but then I thought that this may have to do with the early step when PW processes/build the $config. And indeed, if I set in all site/config.php files the $config->useFunctionsAPI to false, and then in all site/init.php files to true, everything is working fine. Now we can use our sites with the functions API, and we can load as many multiple instances in parallel we want. 🙂 TL;DR site/init.php /** * FOR BETTER SUPPORT OF MULTIINSTANCES, WE ENABLE $config->useFunctionsAPI HERE, * INSTEAD OF THE site/config.php FILE: */ $wire->config->useFunctionsAPI = true; Bootstrapping three different instances, in first step each of them in a single environment: <?php namespace ProcessWire; if(!defined('PW_MASTER_PATH')) define('PW_MASTER_PATH', 'E:/laragon/www/hwm/'); if(!defined('PW_MASTER_HTTPURL')) define('PW_MASTER_HTTPURL', 'https://hwm.local/'); // bootstrap ProcessWire instance site1 (3.0.163) require_once(PW_MASTER_PATH . 'index.php'); mvd([ 'httpurl' => $wire->wire('pages')->get(1)->httpURL, 'instanceNum' => $wire->getInstanceNum(), 'config->version' => $wire->wire('config')->version, 'useFunctionsAPI' => $wire->wire('config')->useFunctionsAPI ]); When running all three in a multi instance environment, they load fine, (no compile error), all with the use for the functions API enabled: <?php namespace ProcessWire; if(!defined('PW_MASTER_PATH')) define('PW_MASTER_PATH', 'E:/laragon/www/hwm/'); if(!defined('PW_MASTER_HTTPURL')) define('PW_MASTER_HTTPURL', 'https://hwm.local/'); if(!defined('PW_SITE2_PATH')) define('PW_SITE2_PATH', 'E:/laragon/www/hwm2/'); if(!defined('PW_SITE2_HTTPURL')) define('PW_SITE2_HTTPURL', 'https://hwm2.local/'); if(!defined('PW_SITE3_PATH')) define('PW_SITE3_PATH', 'E:/laragon/www/hwm3/'); if(!defined('PW_SITE3_HTTPURL')) define('PW_SITE3_HTTPURL', 'https://hwm3.local/'); // bootstrap ProcessWire master instance (3.0.163) require_once(PW_MASTER_PATH . 'index.php'); mvd([ 'httpurl' => $wire->wire('pages')->get(1)->httpURL, 'instanceNum' => $wire->getInstanceNum(), 'config->version' => $wire->wire('config')->version, 'useFunctionsAPI' => $wire->wire('config')->useFunctionsAPI ]); // create a secondary instance from master (3.0.163) $wire = new \ProcessWire\ProcessWire(PW_MASTER_PATH); mvd([ 'httpurl' => $wire->wire('pages')->get(1)->httpURL, 'instanceNum' => $wire->getInstanceNum(), 'config->version' => $wire->wire('config')->version, 'useFunctionsAPI' => $wire->wire('config')->useFunctionsAPI ]); // create instance of a second site (3.0.162) $site2 = new ProcessWire(PW_SITE2_PATH, PW_SITE2_HTTPURL); mvd([ 'httpurl' => $site2->wire('pages')->get(1)->httpURL, 'instanceNum' => $site2->getInstanceNum(), 'config->version' => $site2->wire('config')->version, 'useFunctionsAPI' => $site2->wire('config')->useFunctionsAPI ]); // create instance of a third site (3.0.152) $site3 = new ProcessWire(PW_SITE3_PATH, PW_SITE3_HTTPURL); mvd([ 'httpurl' => $site3->wire('pages')->get(1)->httpURL, 'instanceNum' => $site3->getInstanceNum(), 'config->version' => $site3->wire('config')->version, 'useFunctionsAPI' => $site3->wire('config')->useFunctionsAPI ]);
  • Create New...