Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by MoritzLost

  1. Thanks for the update @d'Hinnisdaël, the new version fixes the issue 🙂 As for the warnings with the Textareas field, that was indeed a bug with the Textareas module. I fact, I encountered this bug a year ago and Ryan fixed it already. Now if only I'd remembered to actually use the updated module ... 😛 Thanks for your help!
  2. @d'Hinnisdaël Great, thanks for your support! I'll install the new version tomorrow, and I'll try your suggestions for the Textareas field 🙂
  3. Thanks! I was hoping the screenshot would do that 😆 Maybe I can give the screencast a go this weekend ... though I'm just now realizing I don't even have a headset any more 😅 Lockdown because of Covid-19 mostly 😅 No but really, the README on Github has two examples, and the first one is basically the client project that started this off. This project is a lead generation platform with multiple contact / data collection forms. Our client's team manages all requests on a Trello board. This works really well once everybody is used to it, they use many custom labels and lists to organize all requests / leads. Currently all the new leads are entered manually, but after the relaunch every request will create both a ProcessWire page and a Trello card for the lead. After additional data is entered through one of the forms, the cards are updates with more information and appropriate labels. This is what the status change handling options are for; if the ProcessWire page is trashed, the Trello card can be archived and so on ...
  4. TrelloWire This is a module that allows you to automatically create Trello cards for ProcessWire pages and update them when the pages are updated. This allows you to setup connected workflows. Card properties and change handling behaviour can be customized through the extensive module configuration. Every action the module performs is hookable, so you can modify when and how cards are created as much as you need to. The module also contains an API-component that makes it easy to make requests to the Trello API and build your own connected ProcessWire-Trello workflows. Features All the things the module can do for you without any custom code: Create a new card on Trello whenever a page is added or published (you can select applicable templates). Configure the target board, target list, name and description for new cards. Add default labels and checklists to the card. Update the card whenever the page is updated (optional). When the status of the card changes (published / unpublished, hidden / unhidden, trashed / restored or deleted), move the card to a different list or archive or delete it (configurable). You can extend this through hooks in many ways: Modifiy when and how cards are created. Modify the card properties (Target board & list, title, description, et c.) before they are sent to Trello. Create your own workflows by utilizing an API helper class with many convenient utility methods to access the Trello API directly. Feedback & Future Plans Let me know what you think! In particular: If you find any bugs report them here or on Github, I'll try to fix them. This module was born out of a use-case for a client project where we manage new form submissions through Trello. I'm not sure how many use-cases there are for this module. If you do use it, tell me about it! The Trello API is pretty extensive, I'll try to add some more helper methods to the TrelloWireApi class (let me know if you need anything in particular). I'll think about how the module can support different workflows that include Twig – talk to me if you have a use-case! Next steps could be a dashboard to manage pages that are connected to a Trello card, or a new section in the settings tab to manage the Trello connection. But it depends on whether there is any interest in this 🙂 Links Repository on Github Complete module documentation (getting started, configuration & API documentation) [Module directory pending approval] Module configuration
  5. Hi @d'Hinnisdaël , thanks for this module! I'm trying it out now and collecting a couple of suggestions. I have encountered two small-ish bugs so far: On Firefox, I get a horizontal overflow in Firefox with the 'Shortcuts' panel in 'list' mode and 'small' size. Doesn't happen in Chrome. The following CSS fixes it for me (even though I haven't checked if it has other unintended consequences yet): .Dashboard__panel { max-width: 100%; } I'm also getting two warnings with the 'Collections' panel when I try to output some text from a Textareas field. Here's the input for the collection panel: 'columns' => [ 'title' => wire('fields')->get('title')->getLabel(), 'c_campaign_parameters.utm_source' => 'Campaign source' ], This results in warnings (even though the output still works): 1× PHP Warning: class_parents(): Class InputfieldText does not exist and could not be loaded in .../FieldtypeTextareas.module:1071 1× PHP Warning: in_array() expects parameter 2 to be array, bool given in .../FieldtypeTextareas.module:1072 I'm not sure if this is a bug in your module or in the Textareas field 🙂 Can you take a look? Thanks!
  6. @Tyssen Stuff like that happens to me all the time 🙂 Glad you got it working!
  7. If the class can't be found, the autoloader probably hasn't been included for some reason. Where are you including the autoloader? Make sure it's loaded before using the Twig classes: var_dump(class_exists('Twig\Loader\FilesystemLoader')); If it doesn't, the autoloader likely hasn't been included yet, or Twig is not installed. Which version Twig are you using? If you're using an older version of Twig 1, the namespaced classes may not exist in your version yet. In that case try to update to the latest 2.X or 3.X version. Have you made sure that the composer.json on your live server actually includes the Twig requirement?
  8. Probably not. If you look at the source code of WireHttp::send (wireSendFile is basically an alias for this), it sends the file by sending the correct HTTP headers for file transfers (Content-Disposition: attachment) and then streaming the raw binary data. JavaScript can trigger downloads but it's a bit more involved and doesn't work in all browsers. It will be way easier to use a normal form submission without AJAX, then it should work as intended.
  9. @a-ok I didn't know that method existed, look like it does pretty much the same as my example code above, so absolutely yes, use it! I would only change the default headers: Since your file is password-protected, you want to set 'Cache-Control: no-store' (or private) so it can't be cached on the network / CDN layer. The method also sets 'Pragma: public' by default, so this should be changed to 'Pragma: no-store' as well (or better yet, removed entirely).
  10. I have now integrated the ProCache branch into the module and released it as version 1.0.0! I have tested the module on multiple sites and it's pretty stable now. But if you do run into bugs, let me know! The ProCache integration is now included, so you can clear out the ProCache page render cache alongside all other caches. Hopefully we can resolve the issue with minified assets, see the previous post. The documentation is now updated with information on all the new methods added in the previous release. Let me know if something isn't working for you!
  11. I have built little forms like this manually a couple of times! It's definitely fun, though building complex forms is a lot more work than one might think, but for small forms you'll be fine. No problem at all - you just need to handle the things that FormBuilder will do. In your example, most notably: Write the HTML for the form. You can try to dynamically generate this, but building exhaustive options for form fields is much work, so for a simple form static HTML will be fine. Handle the result. I'd do that within the template file of the template where your form is output. For a normal form you'd need some form of Spam protection, CSRF protection and other stuff but since in your case you require a password that won't be necessary, since you can just throw out submission that don't match the password. Store the submission, more on that below. Submit the file. For a simple solution, you can just redirect to the URL of the file. I have built something where I wanted to make sure the file can ONLY be accessed through the form. For this, you can put your file in a safe location (outside your webroot) and stream it through PHP once you have checked if the password is correct. Make sure to output the correct header to instruct the browser to start a download. Quick and dirty, based on the readfile documentation: if ($input->post('password_field') === $page->my_secret_password) { $file = '/path/to/file.pdf'; header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename="'.basename($file).'"'); header('Content-Length: ' . filesize($file)); header('Cache-Control: private'); readfile($file); exit; } Honestly, don't overthink this bit. Unless you are expecting thousands of request an hour, you don't need to optimise it. Depending on what you plan to do with this data I might go with a ProFields Table field or a regular template. Those are nice because all content is stored in a single, simple table. This gives you a bit more room to optimise if and when you need to. But if you are really getting so many requests that the server can't handle them, you will probably yield more improvements by building a seperate endpoint that doesn't load ProcessWire at all and instead writes to the database directly. This will be a bit easier with a ProFields Table field, though it really doesn't matter that much. If you are using a ProFields Table, make sure you are not loading the field on your form page, because that will load ALL it's data, that might in fact get out of hand quickly if you have lots of submissions.
  12. Thanks @David Karich! Hm, right now the module is just calling $procache->clearAll() which is supposed to clear everything according to the ProCache store page. Is there another method to clear the minified assets as well? I checked all documentation I could find, a couple of ideas: I don't know how ProCache works with minified assets, but according to this blog post any changes to the CSS & JS files should be picked up automatically, so maybe it's not necessary to clear those? Though of course that is not ideal for a cache clear button 🙂 Judging by the last screenshot on this blog post, ProCache stores minified assets inside /site/assets/pwpc, or is that out of date? Currently, ProcessCacheControl only supports clearing out folders inside /site/assets/cache (so it can't accidentally nuke the files directory because of a misconfigured setting ...). Maybe I could extend that to also allow clearing /site/assets/pwpc. Is that directory path static or can it be changed? Anyway, I'll put out a stable release with updated documentation & the ProCache integration soon! Hopefully the minification issue can also be resolved then.
  13. So I just opened an issue and closed it immediately because I realized that my proposed solution already exists in the form of wirePopulateStringTags 🙂 It works perfectly for my use case, only requiring to use {title} with curly braces instead of title for the first example, which in a way is even more predictable. Those functions should really have better visibility in the documentation 😄
  14. Thanks @Robin S, that was my conclusion as well. I would say that the behaviour in my third case is somewhat unspecified in the documentation – because the string is neither a field name nor a replacement pattern. I guess what I don't like about the implementation is that the distinction between the two cases is done by checking if the string contains curly braces. For my taste, it would be more explicit to check if the passed value is a field name and fall back to the curly brace implementation if it isn't. Though admittedly there are a lot of edge cases with subfields or alternate fields ... Maybe it would be best to add an optional parameter to those methods that forces one specific behaviour. I have considered that, but that will produce an 'incorrect' result (for my use case) in another case. Namely, if the passed value is a field name but the field happens to be empty on the current page, the field name will be output – even though an empty string would be the expected result in that case. So in order to get the expected result for every input, I'll have to: Return the output of $page->getMarkup if it is not empty. If it is empty, check if the original string is a fieldname (or sub-fieldname or similar). If it isn't, output the original string. If it is, output an empty string. I would prefer if that logic was done inside getMarkup. I guess I'll open a feature request for that.
  15. A couple of times I've stumbled over a problem with $page->getMarkup / $page->getText. I'm often using this to parse module settings where the user can either enter a field name or a longer format with field replacements in curly braces. The problem is that entering a static text (not a field name) WITHOUT curly braces always returns an empty string. This seems counterintuitive, and it also presents a problem for those settings. More specific, for a module configuration where the user can enter a string that will be output somewhere. Something like this: echo $page->getMarkup($modules->get('MyModule')->MyTextFormatSetting); This works great for two out of three inputs: title -> Returns the page's title, great. The current title is {title} -> Returns the custom string with the page's title replaced in the end, great. My custom text without replacements -> Returns an empty string, not so great. It's arguable whether getMarkup should just return the original text unmodified in the third case (imho it should). But how do I work around this when working on a module? I can think of two approaches: Add another setting where the user can switch between a static text and a replacement pattern for getMarkup. This is not ideal because it's another setting I have to code and the user has to think about, which should be unnecessary. Fallback to the original string if getMarkup returns an empty string. The problem here is if the original input is in fact a field name and the field is just empty on that field, I'm now outputting a field name instead of an empty string, which is incorrect in that case. I could work around that by checking if the original input is the name of an existing field, but that once again adds more complexity. Is there a better way to do this? Some function I haven't considered? How do you handle this in your modules? Any suggestions would be appreciated!
  16. PageArray inherits from PaginatedArray which inherits from WireArray. WireArray checks for duplicates by default. You can change this behaviour through setDuplicateChecking!
  17. @horst Hm, I hadn't considered that, that makes it more difficult indeed. Come to think of it, most of my sites would have this issue as well - for example, I use a non-standard pagination approach with URL segments, those wouldn't be caught by just using the public URL of the base page; only the first page would be reached. I guess webcrawling would be a way around that, though that is a real can of worms ... Maybe a good compromise would be making the process hookable, like you said. Maybe the method can call a hookable method that returns an array of URLs for each page; by default it returns only the normal URLs, and additional URLs with additional parameters, url segments et c. can be added through hooks. I'll give this a go when I have the time!
  18. @horst Thanks for the feedback. Does warming up ProCache require any special consideration? I liked the approach of HTTP requests because of it's simplicity – i.e. it's virtually identical with a regular page visits, so the normal caching mechanisms can just do their thing. Or will that not work with ProCache for some reason?
  19. @horst Awesome, thank you very much! I'll merge the branch into master soon then. I just need to update the documentation with all the new methods I added in the previous release, then I'll update the module to the first stable release. I'm still thinking about other useful cache actions. I considered a "warm up" method that will just iterate over all the pages and perform anonymous HTTP requests to warm up the template render cache. Does something like this already exist? Would it be useful to anyone? For smaller sites it would be trivial, but for larger sites the module might need some form of rate limiting, batch processing ... not sure if it's worth the effort?
  20. I just updated the module to version 0.5.0! I have now installed it on a couple of sites and it's pretty stable by now. But before I tag a stable 1.0.0 release I would really like to get the ProCache integration working. ProCache integration - Testers wanted If somebody has access to the ProCache module and would like to help me, I just need someone to test the ProCache integration! To get started, download the procache branch of the module on Github and install it . There should be a new "ProCache" option in the module configuration. This field should also tell you whether you have ProCache installed. Check this option. Then go to the Process page through Setup -> Cache Control and click the "Clear all" button. The log output should clear the ProCache entirely. I'd like to know if you get any errors during any of those steps. Also, please check if the ProCache has been actually cleared. Thanks! Version 0.5.0 The new version provides some additional helper methods to check if users can access particular actions and improves the status messages displayed on the process page. In particular, there's a new static method to check if the user can access the module. This is important, because instantiating the module ($modules->get('ProcessCacheControl')) will throw an error if the user does not have the required permission. So this can now be checked with the static method ProcessCacheControl::canUseModule($user). The complete Changelog can be found in the CHANGELOG.md in the repository.
  21. You don't even need to adjust your template, as long as the rows have one common parent you can use the CSS nth-selector: .row { display: flex; flex-flow: row nowrap; justify-content: space-between; align-items: center; } .row:nth-child(2n) { flex-direction: row-reverse; }
  22. @Flashmaster82 That's the same thing. {$page->parent} evaluates to the parent page's ID. The difference is that you're now using "team_page" instead of "sports_team". The query needs to match the name of the field you're using to select the sports team on the profile_page, so make sure to use the correct field names.
  23. I don't completely understand your structure, but you are passing in only a name (not a complete path), so ProcessWire has no way of knowing where in your page tree the $relative page is located. If you use the ID instead, it should work: $relative = $page->parent->id; $event->return = $event->pages->find("template=profile_page, sports_team=$relative");
  24. You need to iterate through all languages and set the name in all of them. After all, they might also have different titles, so you want to use the local title as well. Something like this: function customPageName(HookEvent $event) { $page = $event->arguments(0); if ($page->template->name == 'about-events-single') { $eventDate = date("dmY", $page->global_date_end); $page->of(false); foreach (wire('languages') as $lang) { $localTitle = $page->getLanguageValue($lang, 'title'); $localPageName = wire()->sanitizer->pageName($localTitle . '-' . $eventDate, true); $page->setLanguageValue($lang, 'name', $localPageName); } } } wire()->addHookAfter('Pages::saveReady', null, 'customPageName'); Quick and untested, might need some adjustments, but you get the idea 🙂
  25. @baronmunchowsen Hm, that is true. I don't often use the callback argument, so I haven't encountered that problem yet. The hooked method passes on the argument, but if it's used the WireCache class will still use the normal save() method to save the return value, as you said. I suppose you could replicate the functionality of the protected renderCacheValue method inside the hook method, and execute the fallback function manually instead of passing it on to $cache->get. But for my taste that would be too much code duplication. So yes, I'd say it's best to not use the fallback function with the saveRaw method.
  • Create New...