Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation since 01/30/2022 in all areas

  1. Something I've wanted in ProcessWire for a long time is full version support for pages. It's one of those things I've been trying to build since ProcessWire 1.0, but never totally got there. Versioning text and number fields (and similar types) is straightforward. But field types in ProcessWire are plugin modules, making any type of data storage possible. That just doesn't mix well with being version friendly, particularly when getting into repeaters and other complex types. ProDrafts got close, but full version support was dropped from it before the first version was released. It had just become too much to manage, and I wanted it to focus just on doing drafts, and doing them as well as we could. ProDrafts supports repeaters too, though nested repeaters became too complex to officially support, so there are still some inherent limitations. I tried again to get full version support with a module called PageSnapshots developed a couple years ago, and spent weeks developing it. But by the time I got it fully working with all the core Fieldtypes (including repeaters), I wasn't happy with it. It was functional but had become too complex for comfort. So it was never released. This happens with about 1/2 of the code I write – it gets thrown out or rewritten. It's part of the process. What I learned from all this is that it's not practical for any single module to effectively support versions across all Fieldtypes in ProcessWire. Instead, the Fieldtypes themselves have to manage versions of their own data, at least in the more complicated cases (repeaters, ProFields and such). The storage systems behind Fieldtypes are sometimes unique to the type, and version management needs to stay internal [to the Fieldtype] in those cases. Repeaters are a good example, as they literally use other pages as storage, in addition to the field_* tables. For the above reasons, I've been working on a core interface for Fieldtypes to provide their own version support. Alongside that, I've been working on something that vaguely resembles the Snapshots module's API. But rather than trying to manage versions for page field data itself, it delegates to the Fieldtypes when appropriate. If a Fieldtype implements the version interface, it calls upon that Fieldtype to save, get, restore and delete versions of its own data. It breaks the complexity down into smaller chunks, to the point where it's no longer "complexity", and thus reasonable and manageable. It's a work in progress and I've not committed any of it to the core yet, but some of this is functional already. So far it's going more smoothly than past attempts due to the different approach. My hope is to have core version support so that modules like ProDrafts and others can eventually use that API to handle their versioning needs rather than trying to do it all themselves. I also hope this will enable us to effectively version the repeater types (including nested). I'm not there yet, but it's in sight. If it all works out as intended, the plan is to have a page versions API, as part of the $pages API. I'll follow up more as work continues. Thanks for reading and have a great weekend!
    41 points
  2. This week I've been working on something a little different: developing a new site profile in ProcessWire. Actually, I should probably call it an application profile rather than a site profile, as it's not a website profile. Instead it's a profile for an invoicing application in ProcessWire. Though you would install and run it on a web server, but it would be an independent application rather than part of a website... perhaps something you run in a subdirectory, subdomain, or even localhost. This is something I've been wanting to build for awhile—ever since the invoice service I use raised their rates beyond my budget. So I thought I'd build a replacement that I could use, as well as share for others that might have a similar need. I think it might also be a pretty decent PW profile example in general, too. I'd originally considered building it as a Process module but decided not to for a few reasons. Though the biggest one is that a site profile enables the greatest potential for customization and expansion according to each person's needs. Since you can expand upon it by adding your own fields and templates, or editing existing ones, most can really tailor it to their own needs a lot more easily than they could if it were a Process module. Likewise, since the actual invoices (and invoice emails) are rendered from front-end pages, you can customize the look and feel of them to match your brand very easily. (This is something I always wished I could do with the invoice service I've been using previously) This invoice profile requires nothing other than the ProcessWire core. It has no 3rd party or Pro module dependencies. I've got it largely functional at this stage, though will be putting a couple more weeks work into it before releasing it. I'd like to build in the option for clients to pay an invoice with a credit card (via Stripe) for instance. Below are a few screenshots of the work in progress. First is the page-list which shows the current invoices in the system and their status. (click image to view larger) As you can see, there are also pages for Clients and Settings. The client pages contain all the information about each client that invoices can be created for. The Settings page is where you can edit your own company information, logo and billing preferences. Next is the invoice editor. Here we have a repeater for each line item in the invoice. We also have a repeater for payments. All of the totals add up automatically as you type (Javascript added via hooks). They are also calculated automatically at the server side, so that everything stays consistent whether working with the API or in the page editor. (click image to view larger) At the bottom of the invoice editor you'll see a collapsed input for "Invoice action". This is where you can select actions to apply to the invoice. The two we currently have are "Email invoice to client" and "Email invoice to another address". Next up is what we see when viewing the invoice on the front-end. This is just the output of a template file but it is optimized for printing, saving to PDF and sending through email. I've kept it intentionally simple but of course the logo would be replaced with your own and all markup/styles are fully under your control. (click image to view larger) What I plan to add next are payment options, enabling a client to pay by credit card right from the invoice URL or email. What do you think, is this type of PW profile useful to you or someone you know? I've initially built it towards my own client invoicing needs, but I'm curious what other features you would like it to have? Or do you think it's better to keep it simple so that people can more easily take it in different directions? Thanks for your feedback. Have a great weekend!
    40 points
  3. This new main/master version has more than 220 commits, resolves more than 80 issues, adds numerous new features, performance improvements and optimizations, and consumes HALF the disk space of our previous release— https://processwire.com/blog/posts/pw-3.0.200/ I've just merged the dev branch to the master branch so this new version is available now. I will add the 3.0.200 tag (which should trigger packagist and others) over this weekend or Monday.
    40 points
  4. 140 commits, 55 resolved issues, dozens of new features, eight contributors, and five new pull requests make yet another great new version of ProcessWire. This week I’m happy to announce another new main/master branch version of ProcessWire, version 3.0.210. Like most main release versions, there is a lot here. This post covers some of the most notable additions and improvements— https://processwire.com/blog/posts/pw-3.0.210/
    35 points
  5. I did my first talk ever yesterday @ PHP Meetup Vienna!! Once more everything was a lot more work than I first thought, but I'm quite proud of the result 😎 What do you think? Did I forget something important? It was really hard to put 10 years into one hour... The recording was not planned at first, but I thought I'd just give it a try and everything worked quite well 🥳 If you like what you see please share it with others so that ProcessWire gets the attention that it deserves 🙂 Special thanks to @gebeer for showing me ProcessWire in 2013 🤗
    35 points
  6. Merry Christmas, Happy Hanukkah, and Happy Holidays! The plan is to release a newyear main/master core version. I'm not currently aware of any showstopper issues specific to the current dev branch, but if you are aware of any, please report them in the GitHub issues repo (or reply to an existing issue report), as the dev branch will soon become the master branch. There's not yet a hard deadline, so whether it's end of December or the 1st week of January, we'll have a new release out shortly. The dev branch is very stable right now (likely more stable than the master branch) so it's a good time to get a new version out. I've also been holding off on several larger updates to the dev branch in anticipation of this merge to master and new release, so I've likewise been holding back on any commits that would add more to test. Once we get a new main/master release out there, the dev branch will then get InputfieldTinyMCE merged into it and there will be some JS library updates, along with other larger updates, and those that would need dev branch testing. Thanks for reading and I hope that you have a great holiday weekend and week ahead
    35 points
  7. PAGEGRID – A visual page builder for ProcessWire. Design fully responsive websites (or parts of them) without writing any code. Use ProcessWire's native templates (and fields) to create your own blocks. Rearrange and resize items in a visual way and use inline or modal editing to quickly edit the content of your website. (The demo uses AdminThemeCanvas but it will work just fine with the core Uikit Theme) Try PAGEGRID for free Checkout the online demo. PAGEGRID is not free software. However, you can try PAGEGRID on your local machine or on a test server as long as you need to make sure it is the right tool for your next project. … and when you’re convinced, buy your license. Get it here Download from GitHub Download from Module Directory Requirements ProcessWire 3.0.210 or greater Currently the dev version of ProcessWire 3.0.216 or greater has some bugs with PG. (I have a working fix, and it will be comming soon). Please use the latest master release of ProcessWire for now) Installation Go to “Modules > Site > Add New“ in your admin Paste the Module Class Name "FieldtypePageGrid" into the field “Add Module From Directory“ Click “Get Module Info“ On the overview, click “Download And Install“ On the following screen, click “Install Now“ More install options Module install guide Site profile install guide Get up and running Quick start Create your own blocks or install the PageGridBlocks Module (installs premade templates and fields for PAGEGRID blocks). What's PAGEGRID? page-grid.com – Get to know PAGEGRID. Documentation – Read the official documentation. Issues – Report bugs and other problems. Forum – Whenever you get stuck, don't hesitate to reach out for questions and support. Why I build it ProcessWire is super flexible in itself and lets me build whatever I want. But building a custom website can be a lot of work. For some projects, I've ended up using a lot of templates and fields. To make my pages more flexible, I sometimes build my own little page builder based on the RepeaterMatrix or PageTable module. While these page builders were great for the specific site I was building them for, they were never flexible enough to be used for new projects, so I ended up customizing them frequently. The more complex they became, the harder it became to use them for my clients. After playing around with some WYSIWYG page builder tools, I realized that while they can save me a lot of time, they can also be very limiting or have expensive subscriptions and somehow tie you to their ecosystem. So I decided to build my own page builder based on the most flexible CMS I knew. Concept This fieldtype Renders block templates and adds drag and drop functionality in admin, as well as enable inline editing for text, and file fields. It also let's you manipulate CSS in a visual way to design fully responsive websites (or parts of them) without writing code. The fieldtype comes with an optional style panel to manipulate CSS properties directly on the page. You can customize the panel or disable it completely from the module settings (and just use a CSS file that you include in your template). The data to style the items is stored directly on the item using PW's meta data (no extra fields are created). Don't want to give your client all that power? Use ProcessWire’s powerful permission system to control what your clients can edit. You can then also grant access individually to the style panel, resize or drag functionality using ProcessWire's build in permission system. Features Blocks are just pages Blocks are defined by native PW templates and fields Manipulate CSS grid or flexbox based layouts in a visual way to design fully responsive websites (or parts of them) Encapsulated frontend code (PAGEGRID renders the template of your frontend inside an iframe in the backend) Design and editing features can be disabled for certain roles (using ProcessWire's build in permission system) Inline editing of text, textarea, TinyMCE (supports latest version), ckeditor and file fields Simply drag and resize to manipulate grid items directly inside the backend Manipulate grid columns and rows directly on the page (use any number of columns you want) All style manipulations are saved as JSON and used to generate dynamic styles that you render in your main template (no inline styles) Nested groups/grids (child pages of nested blocks are created under group parent) The style panel supports adding custom classes and assigning styles to them. These classes can be used globally on all pages (a css class is also a page) The style panel supports selecting html tags to style tags globally across the whole site Global blocks work with page reference field (changes on one page, changes all blocks on all pages) Manual and auto placement of grid items blocks and nested blocks can be cloned Redo/undo and copy/paste shortcuts Editing block items in modal sidebar immediately updates frontend (Ajax Save). Define custom icons for your blocks via native template settings (template -> advanced -> icon) Automatic page save (Changes are getting saved via ajax, no need to click the save button) NEW: Option to automatically load lazysizes lazyloader (V 0.1.0) Changelog V 0.1.0: Feature: Option to automatically load lazysizes lazyloader (Module Settings > Plugins). V 0.1.5: Fixed bug: Tabs not working when editing items via modal panel. V 0.1.6: Fixed bug: Setting height in VH unit was not working. V 0.1.7: Feature: Option to hide save button (and use automatic ajax save ) if there are no other fields than PAGEGRID on the content tab (Module Settings > Interface). V 0.2.0: Fixed bug: Custom block wrapper element <p> was not working with inline editor. V 0.2.0: Fixed bug: Inline editor would sometimes not save after clicking cancel and then edit item again. V 0.2.0: Feature: Now it's possible to add classes to elements inside richt text fields via style panel. V 0.2.0: Fixed bug: Inline editor was not working after first item was added to the page (needed reloading the page). V 0.2.1: Feature: Updated PageGridBlocks Module: Using TinyMCE as the default editor. V 0.2.1: Feature: Updated PageGridBlocks Module: Group/container wrapper element can now be changed to <div>, <section>, <article>, <header>, <footer>, <nav>. Thanks to everyone who helped me improve my coding skills and for the support of this great community! Special thanks to @diogo for the valuable feedback and @ryan for this great CMS and his support for the PageFrontEdit module!
    34 points
  8. This is one of those rare weeks where I've got a lot of projects in progress, but all are in the middle, none are at a convenient Friday conclusion for this weekly update. In progress are some core updates, Pro module updates, other module updates, and a client project that's keeping me busy. So I don't have anything new or interesting to report this week, but I like to still check in and say hello, and let you know I'm not running low on coffee or anything like that. 🙂 I hope that you have a great weekend!
    34 points
  9. ProcessWire 3.0.197 resolves 9 issue reports and adds 3 feature requests. For details in resolved issues and feature requests, be sure to see the commit log. I'll cover a couple of my favorite feature requests that have been added this week: New $files->getCSV() method This comes by way of feature request #400 via @bernhard to add something to abstract away the redundant details of reading a CSV file into one simple method call. This simplifies the reading of a CSV file by abstracting file-open, get-header, get-rows and file-close operations into a single method call, where all those operations are handled internally. All you have to do is keep calling the $files->getCSV($filename) method until it returns false. This method will also skip over blank rows by default, unlike PHP’s fgetcsv() which will return a 1-column row with null value. Here's how you use it: Let's say we have this CSV file (first row is the header): Food,Type,Color Apple,Fruit,Red Banana,Fruit,Yellow Spinach,Vegetable,Green Here's how you'd use the new method: while($row = $files->getCSV('/path/to/foods.csv')) { echo "Food: $row[Food] "; echo "Type: $row[Type] "; echo "Color: $row[Color] "; } There are also several $options supported, see the $files->getCSV() documentation page for more. There's also a new $files->getAllCSV() method that does the same thing but returns all the rows in the CSV file in one call. Improvement to InputfieldPageListSelectMultiple Next was feature request #339 that requested adding the enhancement developed by @Robin S (via the PageListSelectMultipleQuickly module) into the core. This enhancement keeps the selectable page list open for multiple selections rather than closing it for each selection. It also better indicates when an item is selected. While I ended up writing it in a different way than Robin S.'s module, the end result is nearly identical to Robin S.'s short GIF screencast below: Also added this week is a new "visibility" option for Inputfields: Open + Locked (not editable), along with some small hook documentation improvements in the Pages class. Thanks for reading and have a great weekend!
    34 points
  10. TL:DR I've updated a PW page we've built 9 years ago for the first time and it's still a solid experience. Backstory Back in May I was on a crowded train somewhere in the middle of Germany. Now working as a "Consultant" who builds slidedecks instead of websites, I happily noticed the men next to me talking about responsive webdesign with his friend. During the obligatory "This train is late" announcement we started to chat. My seatmate, a geography teacher, recently attended a web workshop at a large Hamburg agency. He told me he now understands the value of a CMS for updating their site and he wonders how to build a responsive layout. They don't get paid for this and work on their homepage in their spare time. And they have a Typo3 installation 😅 Back in 2013, together with my friend Marvin, we've rebuild our school website with ProcessWire optimized for mobile devices. Launched in 2014 this was quite an impressive feat including online time tables, a working event calendar (with import feature) and many small nice touches. After my encounter on the train, I checked the page and yes, It's still online and updated daily! The next day I wrote my old teacher a short email if we should have a closer look into the underlying tech and within minutes I got a super happy reply that he is so glad that somebody would help (again). So let's dive into what we've done. Situation First some details about this ProcessWire installation that is updated by a few teacher on a regular basis. Over the 9 years they've wrote nearly 900 news articles and kept more than 250 pages up to date. The asset folder is over 11GB. Build with Processwire 2.4 (?) and lots of janky code we've updated the page once to 3.0.15 somewhere in 2016 quick and dirty. They even used the old admin layout. ProCache, CroppableImages3 and a few other plugins were used. Every single one of them required an update It's used the classical append-template approach with a single big "function.php" included file. It's running on PHP 5.6 and for whatever reason no PHP update was enforced by the hoster (But the admin panel screamed at me) A privacy nightmare: Google fonts embedded directly, no cookie banner and a no longer working Google Analytics tag included The old ProcessDatabaseModule made a database backup every week as planned over all these years. Nice. No hacks, no attacks and all teachers are using their own account with assigned permissions Changelog I've updated the page with a focus on making it stable and reliable for the next 9 years. After making a development copy of the page, I've started working on the following changes: Updated ProcessWire and all modules to the latest stable version. After reloading a few times, no errors encountered Updated the whole templates to make it work with PHP 8.2 Removed all externally hosted scripts, disabled cookies for all regular visitors and introduced a 2-click-solution for external content Reworked a few frontend style issues around the responsive layout, made slight visual changes for 2023 (e.g. no double black and white 1px borders) Ported the image gallery feature to more templates (Big wish of the people updating the site, they've used a workaround) Cleaned up folder and structures, removed a few smaller plugins and admin helpers no longer needed All this was done back in May and - with a big break - completed now in October. It took a few days and most of the time was spent figuring out our old code. Learnings ProcessWire is robust as f*ck. I just clicked "Update" and it mostly worked instantly I nearly removed features for the PHP update. A custom written importer for the proprietary XML schedule was hard to debug and understand (5-dimensional-arrays...). Gladly I've tossed a coin and just gave ChatGPT the php function source and error message and within a single iteration it updated the code for PHP8. The "responsive" CSS framework aged badly. The used 960gs skeleton uses fixed widths for the responsive layout. I couldn't get it be wider than 320px on mobile screens. So the site is responsive but with a slim profile for now. Replacing it would be a complete layout rewrite Result and looking forward The Werkgymnasium site is now updated and live again. It still loads superfast and looks great after all these years. We have a few more features planned to help our editors input new content but overall it just works. Looking forward a few issues remain. ProCache would require the paid update but it still works fine. The layout needs improvement on mobile screens. There is still an error with the pagination. We'll cleanup the code more and then make the whole template public on Github so that maybe a few students after us can continue with the updates. Maybe even rebuild the frontend one day. I hope I can give you an update in a few years again. As a closing note: I'm still grateful for the amazing community here and all the features ProcessWire has to offer. My daily work no longer resolves around websites but PW has a permanent spot in my heart. Thanks Ryan and all the contributors.
    33 points
  11. I agree it is unfair to make comparisons like this. I also don't think it's very nice to come to an open source project's support board and try to convince people to use a commercial CMS. Maybe the fact that a comparison can be made at all is a compliment. But Craft is a big commercial project with a sizable team and lots of resources and money behind it. ProcessWire is the opposite of that and the comparison seems inappropriate. But since you've stated this is a comparison, I'm not sure where the comparison is — you've focused exclusively on what you think Craft does better (by your own preference), but haven't made efforts to point out the areas where PW does better. So it comes across a little bit as an advertorial for large commercial CMS at the expense of a small open source project. Throughout you are stating a preference for something in Craft and claim a similar feature in ProcessWire is "not well thought out." This is wrong. A more honest statement would be that you and I clearly have different preferences, or maybe you don't fully understand something. But that does not mean that something that differs from your preferences or understanding is "not well thought out." I would never commit something to the core that hasn't been really well thought out, that's something I take really seriously. While much of Craft doesn't suit my own (and others) preferences, and may not be "well thought out" according to how I think things should work, I'm not going to join their forum and tell them it's not well thought out. That's because I respect them and trust that it's well thought out, according to their needs and preferences. So when you start telling someone that something they've put a lot of work into isn't well thought out, that's akin to saying that you do not respect them. I make no claims about being perfect at anything, and there is room for improvement in everything. What I take issue with here are the broad, subjective and largely false generalizations, and that's what I'm replying to. I'm also concerned that anywhere that you've quoted me, you've taken a statement by me out of context, extrapolating it as proof for an unrelated conclusion you've made. For example: In that link we are not talking about ProcessWire at all, and instead are talking about the processwire.com website in development, NOT the CMS. Why would you say I'm "opposed to the idea" of accessible development? This is something I'm interested in and passionate about. I don't understand why you are quoting me on one thing and saying another. In that link, I'm writing about a module called ProcessUser and something that is imposed upon it for a specific security purpose, unique to that particular module, and no other. But you have used my statement as proof that building custom features in ProcessWire isn't encouraged or supported. Nothing could be further from the truth. I have never had such a thought. My thoughts and intentions would be exactly the opposite. What you consider an advantage, I consider a major disadvantage. PW puts nothing between you and PHP, by design, that's a major advantage. I certainly would not be happy with Twig integration being a default. Clearly you like using Twig, which is fine for you to have that opinion, and I think it's perfectly fine for Twig to be an option. But I definitely wouldn't want to standardize upon it. Maybe it doesn't suit your preference, but I hope you can appreciate why we don't do things like that in PW. You are comparing two different kinds of caches. You are talking about a template engine cache. In PW there is no template engine, so likewise no template engine cache. Most of the time you would never need such a cache in PW at all. The $cache variable is something different, and while it can also cache markup, it is much more simple than you imply. PW's API is not string-based. You are writing about selectors (and specifically selector strings), not the "API". ProcessWire lets you specify selectors as strings or as arrays. Most prefer to use strings due to the simplicity of it. But this does not mean that arrays are not reliable. And if you use arrays, then there's no need to do value sanitization. But the majority of the time you are using selectors, you are not injecting user input into it either, so I would consider selector strings to be a major advantage for PW the vast majority of the time. And for times that it's not, you don't have to use it. The problem with chaining methods for this is that they are live code, you can't store them. Perhaps it has benefits in Craft, but they would not be appropriate for PW. In PW selectors can be specified as arrays or strings, and in cases where you want to separate the query property from the query value, then that's why we have the array option in PW. And yes, they are reliable, despite your claim that they are not. The same is true in PW. Fieldtypes build the query and sanitize/validate the value to be queried. The only thing PW asks you to do is IF you are using a selector "string" that ALSO happens to contain user input, then just sanitize that user input part with the selectorValue() method. If you are using an array, then such sanitization is already done for you. This has nothing to do with details of a fieldtype, which will do its own validation/sanitization. Saying "clunky" is a subjective and hardly fair statement to make. What might be clunky to you is optimal to others. You are writing specifically about the file translation system, so the whole purpose is to provide an interface to translate your site php files (primarily template files). The interface is geared to focus on that task only, and that's the point of it. I understand you value more layers between things (like with Twig), but I always prefer fewer layers, a more direct approach, so you'll see that throughout PW. If I'm using a file translation system, I want to know what file I'm working with and I want to be able to tell the translator what file to work with. That my preference, and I understand you have a different one. Of course you can, that's who it is for. Yes they are grouped by file, and that's how I prefer it, and I have never had a client have a problem with that. If you have some preference to keep translators/clients out of the admin, you can also ask them to translate from a spreadsheet (exported from PW) and PW will happily read that in and use it. None of those 3 statements is true. Translations may be stored in JSON files, but they can be exported/imported (all files at once) to/from CSV files. Translation files are not stored in "random" locations. They are stored with the language's files, which is a static location identified by its ID. Adding translations in the code editor is not impossible, because where else would you add new translations, if not in the code? If you need a new translation, go ahead and add your __('text') in your code, and it immediately becomes available as a translation. You are welcome to your opinion, but as someone that put a lot of thought and effort into field translations, it's hard for me to take your opinions seriously when you state things like this. Nothing about them is "tacked on" or "not well thought out", quite the opposite. So to me it seems like at worst, you don't understand what you are talking about, or at best (and most likely), you just have an alternate preference. This is fine, but I don't think that's obvious to everyone reading. So please don't make statements like "not well thought out" when you really mean that something doesn't suit your preference, or maybe you don't fully understand it. I appreciate examples but I'm not aware of any field where you need to "add the second language's field manually". This does not sound at all like PW multi-language fields. If you are talking about PW at all, perhaps you are talking about the "language alternate" fields option? If so, this is an option that is there to provide additional flexibility for specific cases, but it is almost never used in my experience. Please don't use it as a foundation for any comparison, as its borderline deprecated at this point and I don't expect many will ever use it. This conclusion is the opposite of the truth. The fact that PW doesn't impose a specific framework upon you means that all options are open. Anything is available to you. It is more open, not less open. It's you and PHP, and anything you can run in PHP you can run in PW. ProcessWire feature approach is built around constant improvement. It is driven by the community and the needs of clients. The development of PW has always followed this approach. I have a job working with clients just like most PW users and so I develop according to what's needed and when. Most of my income comes from client work. I work on the PW core for free, so development usually has to have some crossover with the other projects that I work on. Despite being open source and largely unfunded, the fact that PW and Craft can end up with apparently similar capabilities and feature sets—and the fact that they can be compared at all—I would consider to be a sign of efficiency and that we are doing something right. If you consider our approach "chaotic" then fine, but the accurate terms would be "flexible", "sustainable", "consistent" and "continuous". The approach been very successful for PW as a project. And PW is also one of the longest lasting projects in this area (open source or commercial), and will continue to be because it's not built around money. I don't add features without completely thinking them out. That's silly, why would we do that? I would never commit something to the core that has not been well thought out. I don't understand why you would say this unless you just don't understand it. Nothing committed in the core has been abandoned. Elsewhere, I've abandoned a ton of code, but most of it has never been seen by anyone. When I commit something to the core, I've spent a lot of time working on it and I'm also committing to supporting it, long term, for as long as there is value in it. That's another reason why I take a lot of time to think through anything that gets added. You are welcome to say that you have a different preference, and you can I clearly have different preferences, but please do not suggest something is not well thought out because that is not true. Well, I'm glad you think there are "hundreds" of features that look cool... though not well supported? I don't know what we're talking about. False. The only bugs that don't get fixed are those where they cannot be duplicated, or that don't have a clear solution and seem to be isolated to one person. And I don't know what you mean about "don't work well with each other and so on". ProcessWire's core focus is already a limited feature set, where much is left to modules. The aim is to have everything you might "need" and do it really well, but save things you might "want" for modules. This is one area where it certainly does help to have a big commercial company behind it, with full time documentation writers and such. While they do have a structure and hierarchy, I understand it may not be exactly the way everyone might want it. The site search engine is actually quite powerful and searches the API and all documentation pages, so I recommend that when you want to find something specific. This is fair, and it'll continue to be that way, the blog posts can do heavy lifting in between the time that features are added and documentation is updated (as does this forum). The blog posts do also end up as the linked documentation for features in some cases. I'm okay with it. I understand that if we were a big company it might be odd though. I don't put efforts towards pretending that PW is a big company, I work within the resources we have, putting most of it towards where it counts and less of it towards pleasing critics. The aim is that all versions are compatible, meaning you can safely upgrade from any older version to any newer version. I don't know of any other projects that do this as well as PW, so I would consider it a major benefit. If we get to the point where this is regularly not the case, then we likely would adopt semantic versioning. But the need isn't there at this point in time. Close, but not totally accurate. New versions are currently aimed at a group of new related features or a group of issue fixes. The version number goes into systems that prompt people to upgrade, at the time it is appropriate to do so. They are also for documentation purposes so that we can easily reference them in "since" statements. Lastly, it's useful to have version numbers to reference in blog and/or forum posts. Currently this system of version numbers is the most beneficial one for this project. This isn't what I'd consider a breaking change. This is something where it just asks you to install a module as part of an upgrade to the version, it doesn't break the API or the site, just locks down a specific admin feature for security until you install the appropriate module. And security always comes first in PW. But I don't think there are any actual breaking changes in PW. Again, if it became commonplace like it is in other projects, then we'd likely adopt the same version number approach they do. So perhaps that's something that will come in the future, but we're not at that point. I'm open to it at the appropriate time. A "template file" is a "file" for a "template". I don't know how to be any more clear than that. But yes there are instances where we're talking about template files that I might use the term "template" rather than "template file" since the context is established. I agree that terms like "template" and "file" are fairly generic, and it would be nice if templates were like cars where we could refer to the "car" but also have a label like "wheels" and know we are still referring to the bigger "car" above it. But "file" is a generic enough term that while accurate, needs context. I'll take it as a compliment that you consider RepeaterMatrix to be so valuable. The Pro modules were never intended to be "required" for any site. They are meant to be a luxury or a time saver, but there's nothing you can do with any Pro module that you can't do yourself by some other means. Though Pro modules might save you time in doing it. I've built example modules that show you how to do do just about anything that Pro modules can do, they just might require more of your effort. The original intention for Fieldtypes and Inputfields was that everyone would build their own according to their needs, but I don't know many that do that other than me. Have a look at FieldtypeEvents sometime to see how simple it is to do. I don't share your opinion on this. If you are of the mindset that the page tree reflects the front-end site 1-to-1 then you are in the mindset of a different system. I consider the tree to be essential, a major benefit, as you know everything has a place and hierarchy and you don't have to have various different kinds of navigations or buckets to find them. If you know one thing you know everything in PW. I've never been a fan of different bucket systems and the ambiguity that they introduce. ProcessWire was designed from the beginning to get away from what you are talking about, what I subjectively feel is a mess in other systems (again, my preference). PW aims to be simpler and more flexible than that, though pages can still be browsed as a tree or as buckets, even if the tree is the source. I don't agree with your premise, or the linked post. Having a link to someone else's opinion does not make it right, maybe just right for you personally, that's fine. I would agree that there are benefits to letting the page tree influence your navigation, but there aren't drawbacks to not using it that way either. It may have started that way. While I am currently the gatekeeper in terms of maintaining the core I consider ProcessWire to be a long term community developed project, and it becomes more that every year. Every open source project needs someone to start it, and someone to be a caretaker, ensuring the quality of it, and I see that as my role, which I take very seriously. But this is a team project and one that is much more sustainable long term than a commercial one.
    33 points
  12. This week the core dev branch version has been bumped to 3.0.231. There are about 15 commits in this version relative to the previous. In the dev branch commit log you'll find a good mix of issue fixes and improvements. If you are already using the dev branch, this version is worth the upgrade. If using the main/master branch then it should be a safe upgrade as well, though none of the updates are urgent. And it won't be long till they are also merged to the main/master branch soon too. This week I've also been working on 2 new related modules: FieldtypeDateRange and InputfieldDateRange. These modules allow selection of starting and ending dates to support a date range. It also calculates and stores the number of days and nights for querying and sorting purposes. The "date from" and "date to" can be independently queried from $pages->find(), as can the days or nights. The InputfieldDateRange module can be used independently of its companion Fieldtype module, making it possible to use the date range Inputfield in FormBuilder or other Inputfield forms. One context where the Inputfield might be useful is when selecting travel dates on a front-end form, such as one from FormBuilder. When used as a Fieldtype, you might use it to specify availability of something, start and end dates to publish content, event dates, or any number of other use cases. Below is a screenshot of the Inputfield as well as its configuration tab. The JS-based input widget comes from an existing package that I've made some modifications to, and it works really nicely, with a polished and easy-to-use UI. I originally found it booking some travel online, and really liked the way it worked. I was able to track it down on GitHub here and thought it would be useful to build an Inputfield module around it. It can be set up to work like the core date picker where it appears when you focus in the input, or it can be configured "inline" where it is alway s visible (and the related text input is hidden). In the following screenshot, I've specified that Sundays can't be used for start/end selections and that November 23 is not available. The selected range spans two months. If you want it to span more months, you could click the right arrow in the December calendar to find your desired month, leaving the first calendar in November. In this manner, you can select ranges that span multiple months, or even years: Here's the Inputfield configuration screen so far. All of these settings are hookable as well, as some of them are more likely to be useful dynamically, especially min/max start and end dates, non-selectable dates, etc. (Note the screenshot below does not necessarily reflect the settings in the screenshots above). More on this next week. Have a great weekend!
    32 points
  13. The master/main branch is now updated to version 3.0.225. Early next week I'll be adding a git tag for the version number as well. I usually like to merge dev to the master/main branch first, let it marinate for a day or two, and then tag it. That's because once we tag it, it triggers other services to pick it up and broadcast it. So letting it marinate for the weekend just adds a layer of comfort, for whatever silly reason. That's pretty much how I've always done it. When I did the merge, it reported 511 files changed, 76421 insertions(+), 23539 deletions(-), so there's quite a lot in this version. There's enough, that I'm going to need another week to document it all into a new blog post, which should be ready by this time next week. Our contributors list also continues to grow nicely with this new version. Thanks to all those that have submitted PRs, reported issues, and submitted feature requests. Big thanks to @matjazp in particular who has been helping a lot in identifying, testing, organizing and even coding the solutions for numerous issue reports. More details on this new version next week. Until then, thanks for reading and have a great weekend!
    32 points
  14. In a recent GitHub issue report, I was asked about output formatting in ProcessWire, and where more information could be found about it. I know I've written about it numerous times, and went to locate the documentation page, only to find we didn't have one! Output formatting is such an important topic, so here is everything you need to know. I hope you'll find it simple enough, but also useful and thorough— https://processwire.com/blog/posts/output-formatting/
    32 points
  15. I was in New Orleans at the gymnastics Nationals most of this week. In her age group and level, my 10-year old daughter won 4th overall and 3rd on bars and beam. After a long drive, we're now back home in Atlanta and it's been a very short work week, but there's still a new dev branch version to write about. ProcessWire 3.0.221 continues primarily with minor issue fixes, working towards our next main/master version. Included are 11 resolved issues, 2 PRs, and code contributions from @matjazp and @dotnetic. In terms of new features, this version updates the language translating _n() function to support languages that consider 0 quantities as singular rather than plural in calls like _n('%d item', '%d items', $quantity); Previously this call has always used the plural "items" version for 0 quantities (i.e. "0 items"), which is correct in English, but may not be in other languages like French (as I've learned from issue #1757, though I think it has come up once before too). To define whether a language should consider 0 quantities plural or singular, use ProcessWire's language translation tool: Setup > Languages > [any language] > Find files to translate > wire/modules/LanguageSupport/LanguageTranslator.php ... when translating that file, you'll see the setting at the top labeled "Is zero (0) plural or singular?": That screenshot above also shows another new feature that was added, which is the ability to use Select and Radios fields when defining translatable text. Previously you could only use text, textarea and number fields. Let's say you wanted to have the person translating choose a color name for the language as part of the translation: $color = __('Red'); // What color? type=radios options=[Red, Green, Blue] As before, the "What color?" part is an optional description for the translatable text. Also as before, the "type=..." defines what Inputfield type to use. The supported values are any Inputfield name (minus the "Inputfield" part). Known to work values for this include: text, textarea, integer, float, radios and select. The "options=[...]" is the newly added part, and this enables you to define the selectable options for select or radios inputs. If you wanted to use separate value and label, you can also do that. In the example below, city abbreviations are used for the values and full city names as the labels: $city = __('ATL'); // What city? type=radios options=[ATL:Atlanta, CHI=Chicago, NYC:New York City] Another example is the one we used in the core for plural vs. singular here. By the way, if any of your values or labels need a literal comma, you can optionally use a pipe "|" as the separator rather than a comma. This ability to use Select and Radios is a fairly minor addition, but does open up better support for having certain language settings (rather than just translatable text) be part of language translation packs going forward. The plural vs singular setting for 0 seemed like a good first one to support with this. Next week we'll continue preparing our next main/master version. Thanks for reading and have a great weekend!
    32 points
  16. This week the ProcessWire core version on the dev branch has been bumped to 3.0.207. Relative to the previous version, there are several minor issue resolutions and improvements (commit log). I also recommend this version if you are testing out the InputfieldTinyMCE module, which will likely be merged into the core near the end of the year. Speaking of that module, it also received updates this week with the biggest being the addition of improved lazy loading modules for the Normal (non-inline) editor. Rich text editors are one of the most heavyweight input types you can use, so not having to initialize them all during page load is a major performance benefit, especially when you've got multiple fields using them at the same time. With these new lazy-loading modes, the Normal editor has many of the benefits of the Inline editor in terms of page editor performance, but without any of the drawbacks. The new default setting is to "load editor when it becomes visible". This ensures that resources aren't spent loading editors that are hidden behind editor tabs, fieldsets or language tabs, until they are needed. The other lazy-loading option ("load editor when clicked") is the most aggressive lazy loading option. It shows a preview of the editor content but doesn't actually load TinyMCE until you click the preview to edit it. Lastly, I've also been working on a new module (WireSitemapXML) that generates sitemap.xml output, but in a way that I think is more configurable than the other modules available for it. It also supports multi-language sitemaps, URL segments, various hooks and more. While I've got it in use already, I'm going to spend more time on the documentation before releasing it. That's all for this week, have a great weekend!
    32 points
  17. This week we have some great performance and scalability improvements in the core that enable lazy-loading of fields, templates and fieldgroups, thanks to @thetuningspoon — https://processwire.com/blog/posts/field-and-template-scalability-improvements/
    32 points
  18. This week I'm happy to report that the InputfieldTinyMCE module is now released. It is currently released in the modules directory and GitHub but the plan is it will be merged into the core, likely before the end of the year. No need to wait till then though, as you can start using it today. Please consider the module in beta for the moment, though the TinyMCE library itself is in a stable state. A lot of the work that went into developing this module went into the configuration aspect. Here are a few a more details that weren't covered in last week's post: After installing the module, on the module configuration screen, you can decide whether several settings should be configurable for each field, or if you want to just configure them with the module (affecting all fields): One of things that I thought was important was to make it a lot simpler to add custom classes/styles to the editor. I always found this kind of a pain in CKEditor. So in TinyMCE, I made it so that you can just define these custom styles with the field settings using just simple CSS definitions. InputfieldTinyMCE takes care of converting to a format that TinyMCE can understand (for its menus), as well as the styles to show in the editor. For instance, I wanted to add some common Uikit text classes to a custom "Uikit" group in the Styles dropdown: And here's the result in the editor: The markup produced has the correct Uikit classes in the markup so that on the front-end of my site the output is Uikit ready. You can add 3rd party or your own custom plugins from the module settings: And then you can enable them for any field in the field editor: These are just a few interesting tidbits, but there's a lot more. Also, if you didn't see last week's blog post, that covers a lot more too. Either way, I'd encourage you to download InputfieldTinyMCE, give it a try and please let me know how it works for you. If you come across any bugs, please open an issue report. Thanks for reading and have a great weekend!
    31 points
  19. Continuing from last week's post and discussion, ProcessWire 3.0.218 decouples the modules system from the cache system. Now the modules system maintains its own internal caches (at least once you do a Modules > Refresh). It'll still use the $cache API as a backup (temporarily), but now you can safely export the database without the "caches" table, or even delete the "caches" table, if you want to. It'll get re-created as needed. In this version, work also continued on the new WireCacheInterface (and major updates in WireCache) so that we could support external modules to handle cache storage. This capability is kind of similar to how we support 3rd party WireMail and WireSessionHandler modules. The first example is WireCacheDatabase, which is the default cache storage handler for the core. And today we have a new module called WireCacheFilesystem that replaces the default WireCache database storage with a file-system based storage, once installed. It's not yet clear if there are major benefits one way or the other (cache in database vs. file system), as I've not been able to put all this new code through performance testing yet. I'd definitely be interested to hear if anyone has a chance to test things out. I expect the file system might be faster for reading caches, while the database may be faster for writing caches. At least that's what I found with a few preliminary experiments, but they haven't been very thorough, so take that with a grain of salt. I thought we needed at least 2 examples of classes implementing WireCacheInterface before we'd be ready to support potential 3rd party WireCache modules. I imagine that 3rd party modules getting into dedicated cache options independent of database or file system is where we'll start to see major performance benefits. At least for sites that use the cache heavily. That's all for this week, have a great weekend!
    31 points
  20. On the dev branch this week we have a good collection of issue fixes and feature requests. The dev branch commit log has all the details. One feature added this week which I think could come in very handy is #520 (via @Jonathan Lahijani) which adds the ability to hide individual images in an images field. When an image is hidden, you can see and work with it in the admin, but it gets removed from the field value on the front-end of the site at runtime, effectively hiding it. I know I'll use this a lot, particularly on photo galleries where I may want to remove an image or two from appearing in the grid of photos, but don't necessarily want to delete them. Images can be hidden (or unhidden) from the Actions select of each image, where you'll see a "Hide" option (or an "Unhide" option if the image is already hidden). Hidden images are also dimmed out when viewing the images field in the admin. On the API side, you can hide or unhide images and files using $image->hidden(true) to hide, $image->hidden(false) to unhide, and $image->hidden() to get a true or false as to whether or not the image is hidden. Though this will only be useful on unformatted field values, since hidden images are automatically removed from formatted field values. The same can be used with regular file fields, but we don't currently have a UI/interface for hiding or unhiding items from regular (non-image) file fields. Likely we'll add one soon, but I figured it's likely to get more use with image fields than file fields, so figured we'd start there. More next week. Thanks for reading and have a great weekend!
    30 points
  21. This week core updates are focused on resolving issue reports. Nearly all of the 10 commits this week resolve one issue or another. Though all are minor, so I'm not bumping the version number just yet, as I'd like to get a little more in the core before bumping the version to 3.0.202. This week I've also continued development on this WP-to-PW site conversion. On this site hundreds of pages are used to represent certain types of vacations, each with a lot of details and fields. Several pages in the site let you list, search and filter these things. When rendering a list of these (which a lot of pages do), it might list 10, 20, 100 or more of them at once on a page (which is to say, there can be a few, or there can be a lot). Each of the items has a lot of markup, compiled from about a dozen fields in each list item. They are kind of expensive to render in terms of time, so caching comes to mind. These pages aren't good candidates for full-page caches (like ProCache, etc.) since they will typically be unique according to a user's query and filters. So using the $cache API var seems like an obvious choice (or MarkupCache). But I didn't really want to spawn a new DB query for each item (as there might be hundreds), plus I had a specific need for when the cache should be reset — I needed it to re-create the cache for each rendered item whenever the cache for it was older than the last modified date of the page it represents. There's a really simple way to do this and it makes a huge difference in performance (for this case at least). Here's a quick recipe for how to make this sort of rendering very fast. But first, let's take a look at the uncached version: // find items matching query $items = $pages->find('...'); // iterate and render each item foreach($items as $item) { echo " <!-- expensive to render markup here ---> <div class='item'> <a href='$item->url'>$item->title</a> ...and so on... </div> "; } That looks simple, but what you don't see is everything that goes in the <div class="item">...</div> which is a lot more than what you see here. (If we were to take the above code literally, just outputting url and title, then there would be little point in caching.) But within each .item element more than a dozen fields are being accessed and output, including images, repeatable items, etc. It takes some time to render. When there's 100 or more of them to render at once, it literally takes 5 seconds. But after adding caching to it, now the same thing takes under 100 milliseconds. Here's the same code as above, but hundreds of times faster, thanks to a little caching: // determine where we want to store cache files for each list item $cachePath = $config->paths->cache . 'my-list-items/'; if(!is_dir($cachePath)) wireMkdir($cachePath); // find items matching query $items = $pages->find('...'); // iterate and render each item foreach($items as $item) { $file = $cachePath . "$item->id.html"; // item's cache file if(file_exists($file) && filemtime($file) > $page->modified) { // cache is newer than page's last mod time, so use the cache echo file_get_contents($file); continue; } $out = " <!-- expensive to render markup here ---> <div class='item'> <a href='$item->url'>$item->title</a> ...and so on... </div> "; echo $out; // save item to cache file so we can use it next time file_put_contents($file, $out, LOCK_EX); } This is a kind of cache that rarely needs to be completely cleared because each item in the cache stays consistent with the modification time of the page it represents. But at least during development, we'll need to occasionally clear all of the items in the cache when we make changes to the markup used for each item. So it's good to have a simple option to clear the cache. In this case, I just have it display a "clear cache" link before or after the list, and it only appears to the superuser: if($user->isSuperuser()) { if($input->get('clear')) wireRmdir($cachePath, true); echo "<a href='./?clear=1'>Clear cache</a>"; } I found this simple cache solution to be very effective and efficient on this site. I'll probably add a file() method to the $cache API var that does the same thing. But as you can see, it's hardly necessary since this sort of cache can be implemented so easily on its own, just using plain PHP file functions. Give it a try sometime if you haven't already. Thanks for reading and have a great weekend!
    30 points
  22. I'm off work this week, so I don't have any new ProcessWire updates, but just wanted to wish you a Happy New Year! Looking forward to a great 2024!
    29 points
  23. This week updates continued with various .js files in the core (for jQuery 3.6+ compatibility). A few external libraries were also updated to the latest versions, including jquery-tablesorter, jquery-ui-timepicker, magnific-popup and vex. And finally, InpufieldTinyMCE has been added to the core! That's a lot of updates, but there's not a lot more to write about these updates because we covered the jQuery updates last week, and InputfieldTinyMCE has been the topic of several past posts. But now we've got everything together and running smoothly in ProcessWire 3.0.216. I think we're now ready to focus on getting the next main/master version out in the coming weeks. There likely won't be an update next week because I'll be traveling for a few days, but will be back to a regular schedule the following week. Thanks for reading and have a great weekend!
    29 points
  24. This week we take a look at a new rich text editor for ProcessWire, why we chose it, some highlights, screenshots, and why we think you’ll like it— https://processwire.com/blog/posts/new-rte-for-pw/
    29 points
  25. This last week my wife and daughter took a trip to NYC and it was my daughter's first time there. I was browsing around online looking at things they could do and so I visited the Guggenheim museum website to look into that option... I've always been a fan of the building, a Frank Lloyd Wright masterpiece. In addition to New York, I learned from the website that Guggenheim also has museums in Abu Dhabi, Bilbao and Venice, so I clicked through to view them as well. I really liked the Venice Guggenheim website, which had a much nicer website than the other locations. It was such a nice site that I was curious what they were running, so I viewed the source and... not WordPress (like the others), but ProcessWire. What a nice surprise. Then I was curious about who made such a nice site and there was a credits link in the bottom right corner that says the site was made by basili.co, nice work! It's always fun to come across a ProcessWire powered website randomly like that, and I thought you all would enjoy this one too. This week there are fairly minor updates on the core dev branch. Though the updates include one I've been meaning to do for a long time: improve the API for processing Inputfield forms. Previously there's been no way to check if a form is submitted, short of checking an $input variable yourself. Today I committed an update that adds a $form->isSubmitted() method that solves that, and more. It can identify which form was submitted, which submit button was used, and it also performs additional checks to make sure it's a valid submission before deciding that it's a form worth processing. It improves reliability, accuracy and security. Next week I'll be updating several of the admin forms to use it, among other updates. A few other useful helper methods were added to the Inputfield forms API as well. I realize that these updates may only be of interest to module authors, but I like keep you up-to-date with the week's updates either way. Thanks for reading and have a great weekend!
    29 points
  26. This week I've continued work on the page versions support that I wrote about last week. While the main PagesVersions module needs more work before it's ready to commit to the dev branch and test externally, it is so far working quite well in internal testing. I mentioned last week how it will support an interface where Fieldtypes can declare that they will handle their own versions. That interface has been pushed to the dev branch as FieldtypeDoesVersions. I've also implemented it with the Repeater Fieldtype, which is visible starting here. Repeaters are so far working really well with versions! As far as core Fieldtypes go, Repeater, PageTable and FieldsetPage are likely the only ones that will need custom implementations. For ProFields, RepeaterMatrix already works with the implementation in the core Repeater (already tested). It's possible that other ProFields will not need custom implementations, though not yet positive. The module that provides version capability is called PagesVersions and the plan so far is to make it a core module that provides API version support for pages. A separate module provides interactive version support in the page editor. I've built this module initially so that I can test versions more easily, but it'll be expanded to provide a lot more. Below is a screenshot if what it looks like in the page editor Settings tab so far: As you can see, you can Edit or Restore any existing version. You can also create a new version from the Live version, or any other version. And of course you can view and delete any versions. When you Restore a version, it essentially replaces the live version with the one that you are restoring. All of this can be done from the module's API as well. Note that the API is provided by a $pagesVersions API variable that is present when PagesVersions module is installed. The API method names and such are a bit verbose right now but may be simplified before it's final. // Get page and add a new version of it $page = $pages->get(1234); $page->title = 'New title'; $version = $pagesVersions->addPageVersion($page); echo $version; // i.e. "2" // Get version 2 of a page $pageV2 = $pagesVersions->getPageVersion($page, 2); // Update a version of a page $pageV2->title = "Updated title"; $pagesVersions->savePageVersion($pageV2); // Restore version to live page $pagesVersions->restorePageVersion($pageV2); // Delete page version $pagesVersions->deletePageVersion($pageV2); Thanks for reading! More next week.
    28 points
  27. After 8 months in development we are excited to bring you ProcessWire 3.0.226 main/master. This version has a ton of great new features, improvements and optimizations, plus more than 100 issue fixes. This post takes an in-depth look at highlights from this great new version. While there's even more in this version than is covered fully here, we hope this gives you a good taste of what you'll find in 3.0.226! https://processwire.com/blog/posts/pw-3.0.226/
    28 points
  28. Sometimes you need to execute a slow task after some event occurs in the PW admin, and normally you have to wait for this task to finish before you can continue using the admin. This is because PHP is "blocking", meaning that while one thing is executing nothing else can execute. There are potentially lots of different kinds of tasks that could be slow, but just as an example suppose you want to generate resized variations of images on a page, and there are a lot of images. You might have a hook like this so that any non-existing variations are created when the page is saved: $pages->addHookAfter('saveReady', function(HookEvent $event) { /** @var Page $page */ $page = $event->arguments(0); // When a gallery page is saved if($page->template == 'gallery') { // Create an image variation for each image foreach($page->images as $image) { $image->size(1200, 1200); } } }); When you save a gallery page in the PW admin, the admin will be unresponsive and will only load again after all the variations have been created. I wanted to find a way for slow tasks to be triggered by events in the PW admin and for the website editor not to have to wait for the task to finish before continuing with other work in the admin. Inspired by this StackOverflow answer I came up with the following solution that seems to work well. Using the image variations task above as an example... First we make use of the URL hooks feature to set up a URL that can trigger tasks to run when it is loaded: // A URL that will trigger tasks when loaded $wire->addHook('/run-task/', function($event) { $input = $event->wire()->input; // A simple check to avoid unauthorised access // You could implement more advanced checks if needed if($input->post('key') !== 'cTdPMBQ7x8b7') return false; // Allow the script to keep running even though we have set a short WireHttp timeout ignore_user_abort(true); // The "create variations" task if($input->post('task') === 'create-variations') { $page_id = (int) $input->post('page'); $p = $event->wire()->pages->get($page_id); // Create an image variation for each image foreach($p->images as $image) { $image->size(1200, 1200); } return true; } return false; }); Then in the Pages::saveReady hook we use WireHttp to load that URL and post parameters that define what task to run and anything else needed for the task (in this case the ID of the page that has been saved). $pages->addHookAfter('saveReady', function(HookEvent $event) { /** @var Page $page */ $page = $event->arguments(0); // When a gallery page is saved if($page->template == 'gallery') { // Load the /run-task/ URL using WireHttp $http = new WireHttp(); // Set a short timeout so we don't have to wait until the script finishes // Timeout values shorter than 1 second can be tried once a core issue is fixed // https://github.com/processwire/processwire-issues/issues/1773 $http->setTimeout(1); $url = $event->wire()->config->urls->httpRoot . 'run-task/'; $data = [ 'key' => 'cTdPMBQ7x8b7', 'task' => 'create-variations', 'page' => $page->id, ]; $http->post($url, $data, ['use' => 'curl']); } }); By doing it this way the task runs in a separate request and the website editor doesn't have to wait for it to finish before they can continue working in the PW admin.
    28 points
  29. The new dev branch version 3.0.222 contains about 20 commits and 16 issue resolutions. In terms of new features, last week I mentioned some upgrades to WireHttp, and below are this week's additions: Multi-language month and day names The WireDateTime class (aka the $datetime API variable) has been updated to support multi-language month and day names. Now all month and days are translatable in the WireDateTime file (/wire/core/WireDateTime.php). So if you request any date in a format that uses month names or abbreviations, or day names or abbreviations, they now support multi-language, whether you requested it from the wireDate() function or the $datetime API variable. ProcessWire has long supported multi-language month and day names when using a PHP version prior to 8.1 and you've requested a strftime date format that uses them. But PHP 8.1 dropped the multi-language supporting strftime() function, without leaving a suitable replacement. PHP's IntlDateFormatter can't be relied upon since it's not always compiled with PHP. But as of PW 3.0.222, now we have a suitable replacement. Though it does require you to translate the 7 days and 12 months for file /wire/core/WireDateTime.php using ProcessWire's language translation tool. Note that unlike the previous strftime() solution, the new solution no longer requires you to use strftime() format codes and you can instead use regular date formats and they will be translated automatically. New conditional hooks that match by argument type Another new addition this week is support for conditional hooks that match by argument type. I think this is especially useful combined with ProcessWire's custom page class support. It enables you to make a hook apply only to methods containing arguments of a specific type. For instance, if you had a custom page class "ProductPage" for template "product" and you wanted to capture the "Pages::saved" event for pages of that type (ProductPage) you could do so like this: $wire->addHook('Pages::saved(<ProductPage>)', function($event) { $product = $event->arguments(0); /** @var ProductPage $product */ $event->message("ProductPage '$product->title' has been saved"); }); In addition to supporting class or interface names, you can also specify regular PHP types such as <array>, <string>, <int>, <object>, etc. For more details on this type of hook see the new Conditional hooks that match argument type section of the Hooks documentation. Thanks for reading and have a great weekend!
    28 points
  30. Before the recent and major core updates to WireCache and Modules, we were on track to get a new main/master version out. I'd like to get back to that, as we are now 10 dev versions ahead of the main/master branch, and with some pretty good and major improvements. That's why I've been focused largely on minor issue fixes the last couple of weeks, getting into more of the fine tuning stuff, and likely will be the next couple of weeks as well. Thank you for opening issue reports as you come across stuff to report. Thanks also to @matjazp who's been helping out in the issues repo, maintaining existing reports and often helping to solve them too. I'm thinking we may have a new main/master version ready soon as July, next month. Most of next week I'll be in New Orleans attending the gymnastics nationals where my 10 year old daughter is competing. Since I'll be out of town, there likely won't be a lot of commits next week. Though there may be enough to bump to the next version, 3.0.221, I'm not sure yet. In any case, have a great weekend and week ahead!
    28 points
  31. The ProcessPageList module now has a configuration setting where you can select pages that should not be shown in the page list. For example, maybe once you've set up your 404 page, you don't really need it to display there anymore, except maybe in debug mode. Or maybe you don't ever need the "Admin" page to display in the page list. This new feature lets you do that, and for any page that you decide. Next, a "Usage" fields has been added to the "Basics" tab in the Field editor, just like the one in the Template editor (requested feature #445). This shows you what fields are using the template. It's essentially the same information that you'll find in the "Actions > Add or remove from templates" feature, but easier to find, especially for people newer to PW. That's all for this week, I hope you have a great weekend!
    28 points
  32. In the last couple of weeks I've been working on the page versions support in ProcessWire (recap here and here). This week the new PagesVersions module was committed to the core. Though please consider it very much "beta" at this stage. Along with this, the core dev branch version was bumped to 3.0.232. The API reference page for PagesVersions is now live here: https://processwire.com/api/ref/pages-versions/. Note that the module is not installed by default, but once running 3.0.232, it can be installed by going in your admin to Modules > Wire > Pages > PagesVersions. In addition, a related development module named PagesVersionsPro has also been released. This module uses the new API from the core PagesVersions module. This module will eventually be merged with or replace ProDrafts. The new PagesVersionsPro support board and module is currently visible to ProDrafts, ProFields and ProDevTools subscribers here. Unlike ProDrafts, PagesVersionsPro gets all of its version abilities from the core, and instead just focuses on providing an interactive interface to them in the page editor. To word it another way, the module does not extend the PagesVersions module in the way that ListerPro extends Lister. Instead, it just provides a web interface for it. I think this is a better long term and more sustainable strategy for handling version support. Core version 3.0.232 also adds version support for nested repeaters and FieldsetPage fields. Support was added in those Fieldtypes directly. Still remaining are PageTable (core) and Table (ProFields), both of which will need their own implementations for versions like Repeater and FieldsetPage needed. But following that, there won't be any unsupported fieldtypes to my knowledge. ProcessWire Weekly published its 500th issue! Congratulations and big thanks to @teppo for his incredible work with ProcessWire Weekly, it is truly outstanding! Thanks for reading and have a great weekend!
    27 points
  33. This week we've got a few minor issue fixes and a couple of pull request additions on the dev branch. Pull request #251 thanks to @Jan Romero added a download button to the thumbnail images in InputfieldImage. I wasn't sure we really needed that, but really liked his thinking behind it, which was envisioning the ability to add more custom buttons/actions for images. So while I didn't specifically add the download button, I added the proposed system for adding any custom buttons, and then applied that same thinking to some other parts of InputfieldImage. And we'll talk about how to add that Download button here. 🙂 First, let's look at how you might add your own download button, and note we're using this as just an example, as you might add any kind of button this way. A new hookable getImageThumbnailActions() method was added for this purpose. So here's how you might hook it (in /site/ready.php) to add a download button: $wire->addHookAfter('InputfieldImage::getImageThumbnailActions', function(HookEvent $event) { $image = $event->arguments(0); // Pageimage $class = $event->arguments(3); // class to use on all returned actions $a = $event->return; // array $icon = wireIconMarkup('download'); $a['download'] = "<a class='$class' href='$image->url' download>$icon</a>"; $event->return = $a; }); With that hook in place, here's what it looks like when you hover a thumbnail image. And if you click that Download icon, it downloads the file to your computer: or in list mode (download icon appears in right corner next to trash): I was thinking it would be useful to also be able to add custom actions after you click the thumbnail, and it shows the image edit features. So let's add a Download button there instead, by hooking the new getImageEditButtons() method: $wire->addHookAfter('InputfieldImage::getImageEditButtons', function(HookEvent $event) { $image = $event->arguments(0); // Pageimage $class = $event->arguments(3); // class(es) to use on all returned actions $buttons = $event->return; // array, indexed by action name $icon = wireIconMarkup('download'); $buttons['download'] = "<button class='$class'><a download href='$image->url'>$icon Download</a></button>"; $event->return = $buttons; }); And the result looks like this (see new Download button after Variations button): We also have that Actions dropdown that you see in the screenshot above. This is already hookable but we've not had any good examples of it. In this case, you need two hooks: one to add the action to the <select> and another to handle the processing of the action when the page is saved. So in our next example, we'll demonstrate how to display verbose EXIF information about whatever image(s) the action was selected for. In this first hook, we'll add the action to the Actions <select>: // Example of adding an “Get EXIF data” action to the <select> $wire->addHookAfter('InputfieldImage::getFileActions', function(HookEvent $event) { $image = $event->arguments(0); // Pageimage if($image->ext == 'jpg' || $image->ext == 'jpeg') { $actions = $event->return; // array $actions['exif'] = 'Get EXIF data'; $event->return = $actions; } }); And in this next hook, we'll handle the action, which gets called when the page editor form is submitted: // Example of handling an “Get EXIF data” action $wire->addHookAfter('InputfieldImage::processUnknownFileAction', function(HookEvent $event) { $image = $event->arguments(0); $action = $event->arguments(1); if($action === 'exif' && file_exists($image->filename)) { $exif = exif_read_data($image->filename); $event->warning([ "EXIF data for $image->name" => $exif ], 'icon-photo nogroup'); $event->return = true; } }); And here's what it shows after you hit save (for any images that had the action selected): The screenshot above is truncated because it was about twice is big as what's above. All the above code examples are also included in the phpdoc for each of the relevant hookable methods in the InputfieldImage module. For another recent useful addition, be sure to check out ProcessWire Weekly #454 (last week) which covered some new options available for the language translation functions like __text('hello'); where you can now tell it what kind of input type (and how many rows) to use in the admin translation interface, via inline PHP comments. Thanks for reading and I hope you have a great weekend!
    27 points
  34. This week we have ProcessWire 3.0.201 on the dev branch which includes a couple minor fixes but also a couple of useful additions: There are new "Tab" field visibility options available for any field in the page editor. This makes the field display in its own page editor tab. It saves you from having to create a new/separate Tab field just to wrap around an existing field to make it display in a tab. So far I've found it particularly useful with ProFields (Combo, Table, Textareas, RepeaterMatrix) as well as the core Repeater, FieldsetPage and Images fields. For instance, I have a Combo field labeled "SEO" that lets me edit browser_title, meta_description, canonical_url, etc., and now I can add that field to any template and pages using that template have their own "SEO" tab. Sure you could do this before by creating a separate tab field with an "SEO" label, but now it's a lot simpler/faster, as any field can now display as a tab on its own. Like with the other visibility modes, also included are options to make the tab load dynamically on click with ajax or make the value non-editable. You can also optionally specify a label for the tab independently of the field label. This is because usually you want tab labels to be very short (1 word is best) whereas field labels have no such need. Please note that this new Tab option is exclusive to the page editor, and in order to work the field must not already be in a tab. Also added this week is a new $page->getMultiple() method. This method works the same as the $page->get() method except that it lets you retrieve multiple page property/field values at once and returns them in an array. For example: $a = $page->getMultiple([ 'foo', 'bar', 'baz' ]); list($foo, $bar, $baz) = $a; It also accepts a CSV string: $a = $page->getMultiple('foo,bar,baz'); By default it returns a regular PHP array, suitable for using in list() like the first example. But if you want it to return an associative array instead, then specify true as the 2nd argument: $a = $page->getMultiple('foo,bar,baz', true); echo $a['foo']; echo $a['bar']; echo $a['baz']; I find this method useful in reducing the amount of code/lines necessary in many cases, and most often I use it in combination with a PHP list() call, i.e. list($title,$subtitle,$body) = $page->getMultiple('title,subtitle,body'); That's all for this week. Thanks for reading and have a great weekend!
    27 points
  35. The TinyMCE 6 rich text editor opens up a lot of new and useful abilities for ProcessWire users. In this post, we'll take a look at a few of them, and how you can start using them now, with a focus on those that are unique to ProcessWire's implementation of TinyMCE— https://processwire.com/blog/posts/using-tinymce-6-in-processwire/
    26 points
  36. If you haven't yet noticed it, @teppo has hit the 500th issue of PW Weekly! That is a ridiculously massive milestone and an amazing achievement, and after some quick maths, also tells me that he's held strong for almost 10 years now! I'm not sure what's more surprising, that he's managed to keep it going continuously for this long, or that I remember when he started it... That's a long darn time. I may not be a hugely active member of the community, but I'm darn proud to be a part of it regardless. Thank you so much for your devotion to the PW Weekly project, @teppo!!!!
    26 points
  37. I posted a (rather lengthy) comment about some of the ways I work with my clients. I'll be posting some of that here where reading it in context can help the message as a whole. I've been a web designer/developer for ~15 years in many capacities like freelancing, in-house employee, and now at my own one-person company (I'll get into why that's different than freelancing). I've been the new guy on the bottom rung of the ladder, and a director at an ad agency. I don't think that I'm special or that I have it all figured out! I feel this comes from a culmination of experience, long hours, mistakes, and trying my best. I'll group some topics together and give some briefs on each: on being a web professional, building value/client relations, and yeah things don't always go well. Building skills in these areas may help boost performance in things like getting clients on board with ProcessWire, differentiating yourself from other web services, being confident in what you charge, and building both a great reputation and long-term relationships. Get on the bus, we're leaving our comfort zones. Here comes the disclaimer. How and where you work matters. The market you operate in matters, competition, local economy, etc. That's why I'm not going to say "here's how to come up with what you should charge" or "this one neat trick will change the game". These are my experiences, I think some of what I share will be things you can implement yourself, some may inspire you to think of something different, and other stuff might just be rubbish. I also think that knowledge unshared is knowledge lost- so please share your critiques, experiences, and suggestions below. Your opinion and experience matters! Onward! Note- my language will tend to lean towards freelancers and individual operators but if you're a formal employee this all 100% applies to you as well. Take a moment to envision the company you work for as your client. It becomes relevant very quickly. On being a web professional Being a web dev isn't easy. Taking anything you love (going to make an assumption there) and doing it professionally means doing what you like and slapping on a bunch of stuff you don't to make it work. It also means you need to up your game in places that involve things that "orbit" web development. It is always a good idea to break focus and bring in new skills that complement and increase your expertise. This is necessary so you can be more than a really good developer- you can become an expert. An expert professional proactively learns as much as possible, they can speak with authority in many areas related to their work through verifiable fact and with consideration for others and their needs. A professional works to be good at what they do but also has skills in multiple areas that allow them to do that. It means the difference between building a website and building an effective website. A professional values: Being a clear communicator. Always #1. Being an educator Being a solution Being a student Some of those seem obvious, so let's unpack 'em. Being a clear communicator means more than speaking well. It means conveying your ideas in a way that others can understand and appreciate. It also means working to understand others because that will affect what you say next. Communication requires translating your technical knowledge into layman's terms and rather than stop at stating a fact or good idea, following up with why. This helps others value things as much as you do and shows respect for others in that you believe that they deserve to know. You are a translator you modify your attitude and approach based on how other people are engaging you by being aware and paying attention. Being an educator means bringing others in on your knowledge. Education helps avoid arguments and shows that other people deserve to know more about what you do. I told a client the other day that there are a lot of people who do technical work that don't take the time to educate those around them, that means what you're doing is just a black box of mystery to them. How can they value what you do if they don't understand it? People have become comfortable with "well I'm not smart enough to do that" or "that's too complex for me", I start with the idea that everyone is capable and it is up to them to find their limits. We aren't teaching them how to program, but we should let other people in on things they might care about. This has to be done in a way that the person you are talking to feels like they are being elevated and not become embarrassed or have feelings that they are ignorant for not knowing something. Example: A client in a meeting started reviewing the mockup and picking it apart. "I don't like the color of that button, and why is it located there? Maybe we should move X above Y. I want the form over here not at the bottom." I addressed each of their concerns. I explained that the button is located there because we know from studying user behavior that it is more likely that people will engage. The color of the button is also a UI strategy, if you look across the entire site you'll see that buttons that do something we want them to do are the same color. The "Menu" button is the same color as the "Sign Up" button, we'll have encouraged interaction by normalizing the experience and by mentally associating that color with action. The background of the call to action form at the bottom of the page is the same color as the button- because it indicates an action that you should take. Being a solution means either providing the solution, or if it isn't possible, brainstorming an alternate option. My least favorite situation is the "yes or no" decision. I try to provide a "yes or yes", where we have two options that can address a concern- even if one isn't as good as the other, or isn't what someone had in mind- you have shown that you are here and ready to work on overcoming a challenge. That makes you and your client a team. A "yes or yes" situation means that you have "become the solution", because that's how people will think about what you bring to the table. This one is worth an example from an experience I just had the other day: The client puts together events and sells tickets online. It's a reasonably large event that means a lot of people buying tickets. A lot of people were buying at the last minute, tickets sell out, and people rushing to buy may need help under pressure, both mean unhappy customers. This means a big influx of customer service requests that are difficult to handle. So: "We are trying to think of a way of how to change the shopping cart system to fix this issue but not sure how." Yes/No - "We could work on that but it may be complex work and will be a challenge to solve the problem by the next ticket date. It's up to you whether that's worth it." Yes/Yes - "Yes it's certainly possible to work on the store, we could also consider having an email sign up form on the website and then send an email when tickets go on sale, then reminders so that it can make it easier on everyone to space out the purchases and prevent last minute pressure. I'm open to both, what do you think?" I worked on a Yes/Yes solution, and they felt a lot better, and they no longer have to worry about it. I also communicated and educated by pairing my suggestion with a clear "why it's a good idea", and then I invited their input after sharing. They're signing a retainer contract with me this week. Being a student seems obvious, but it means being an effective student. We learn how to code better and try new things but it's important to get out of your box. This allows you to be more of an authority on web overall and others will see that as something they can and should trust. It's easy to study what you like, but sometimes you gotta take the classes you don't like to graduate... Here are a few: Get to know how to design websites that work. Learn UI best practices, learn about what parts of web design actually drive conversions things like speed, the number of fields on a form, effective calls to action, the difference between a web developer and a web professional is knowing how to merge what you build with what it has to accomplish. I don't do SEO services, but I have taken a lot of time to study it and understand how my work can be the absolute best when it comes to future performance. It goes beyond semantic HTML. Be familiar with what Google ranks by, the things that matter, and understand what is more important than others. It will affect the structure of the site, it means you will be doing things like creating pages that you probably wouldn't think to. Be good at technicals! Sure you've got a good looking site, but have you truly taken time to study typography? Off the top of your head, do you know what the most effective width of paragraph text on a page leads to more reading by visitors? Do you know an effective length of copy? Learn human/web psychology. How do colors affect perception? What if animations aren't just for making things pretty and cool. etc. Read and study stuff from great people like Mike Monteiro's "Design is a Job" because it will open your eyes a lot to the work you should be doing to support the work you're already doing. Also go watch his video titled "F*ck you, pay me" (spoiler: bad words) Before every project I assume that web design changed and it's up to me to check in on the latest information. Google "web design best practices 2023" before designing, head over to Stitcher.io to check out the latest that PHP has to offer and great tips- using new features may save you time, make your code ready for the future, and keep from using something that will be deprecated (WHY IS MY SITE BROKEN? YOU JUST BUILT IT!). I'm serious. Every single project. I assume my knowledge is out of date in some way. Remember: being honest and saying "you know, I'm not sure but I'll research that and get back to you" or "I'm unfamiliar but that's not something I can't figure out" is a hallmark of a trustworthy professional. Do not be a snake oil salesman, do not lie to get the job, don't be a know-it-all. Learn to defer to others who have more experience than you, for me those are SEO specialists, SEM specialists, and sometimes graphic designers. This shows respect for the work others do and you may get some partners to work with in the future. I have SEO and SEM people I trust and can recommend at the drop of a hat. This also makes you a solution, because you have others ready to help you solve problems. If you get caught BSing your way through something, you won't get away with it. Eventually they'll find out and you won't work with them again. I know people who have dropped off the map because of their arrogance or inability to be humble, you know who gets the phone call for work? Me, not him- and some of the people I work with have known him longer. Building value/client relations If you've made it this far in this ridiculously long post, you'll guess why this section comes after being a web professional. Using communication, education, solutions, and a student are pretty much the only way you can build value. Building value validates your hourly rate, or the price for a project. Those skills create intangible value, "my web person is more expensive, but they're honest, open, and always works with me to get what we need done even when I'm not sure what to do." Be mindful that if you wish you could charge more, consider starting from the basics and build more value. Keep in mind that your clients have a job. They have a business to worry about, they probably need to go pick up their kids from school, payroll is due, and why are sales down this month?! Doing your best to make their experience working with you low stress and relieve them of extra work is invaluable. To build value and establish strong client relations you have to stop thinking like a developer and start thinking like a business- PLOT TWIST: not your business, your client's business. Your work needs to reflect that this is more than a website or web application, it's going to solve problems and be a net gain for their organization. You need to think as if you had an office down the hall, act as if their deadlines matter, through the way you work with clients they should feel like worrying about a website is off the table and they can get back to what their real job is. You know what matters to you? Their profits. What else matters? Their employees effectiveness, their customer satisfaction, etc. Your website/app may highly impact all of those things (and probably will). I had a manager tell me after a presentation for a new product page on a website "I was really impressed, you think like you own a business". Mission accomplished. My response? "I really appreciate the compliment, but it really is a culmination of the work you, me, and the rest of the team have done. I really appreciate you helping move the project forward." Most of the following about initial client meetings and writing a proposal is taken from my other comment so you can skip it if you've read it already. Building value starts from the first time you talk about a website. When we first meet I work to lead the conversation in a way that gets me as much information possible to do the best work I can, to let clients know that I'm here for the "big picture", and to get them to think about what their next website means for them and how much it's worth. In my initial meeting I type a lot of notes and I always discuss the following 7 topics: This may sound odd, but what does your business do? I've looked at your current website, but would like to hear that from you. (There's a chance they haven't updated their current website due to reasons we've talked about here, or that the content doesn't do a good enough job). What are your plans over the coming year? Do you plan on expanding to new locations? New products/services? (Not always, feel the client out to see if they're positioned for this- it also lets you think about whether you need to consider this for the site architecture/code) What do you want visitors to do when they get to your website? What does success look like? Filling a form? Calling? Getting them to your online shop? Visiting your location in-person? Stick around for ad revenue? Explain that websites are supposed to do things with purpose. Open up the conversation about how a website is not a brochure, it's a live business asset that establishes brand strength, is often first impression of a business, and because we just discussed what conversions look like in the previous question- a tool that works 24/7 on their behalf. What do you like about your current site? What don't you like about your current site? Is there something that you want your website to do now that it doesn't now? Get everyone in the room to think about how this isn't a replacement website, we're leveling-up here and it's time to get strategically creative. You'll see that all requires communication, education, solutions, and a being a student. After this, I talk about my values and what is important to me when working with clients. Think about the typical idea that "programmers are hard to work with" or "the IT guy is a jerk and is abrasive". We need to overcome that with new potential clients because it's safe to assume that they've had some not-great experiences. I talk with them about these things that matter most to me: Communication. Always #1. They already know that I've taking the time to communicate, now they know that it's my priority and it makes them realize how much we've been talking about them. This is another thing that I can almost guarantee has not been said to them. Ownership. Businesses/people should own their properties and assets. True ownership means being able to use and update it. If there are services along the way (like maybe Google Tag Manager) or a new hosting company then it should be an account their business owns and I'll guide them through any process to do so. If I were to be unavailable someday- you won't be stuck with a website that was dependent on me. Performance. Re-iterating the need to aim for conversions. Adhering to accessibility rules for legal and user friendliness reasons. Making the site 100% (like Google Lighthouse 100%) SEO ready when it comes time for a specialist to optimize. These questions almost never fail to get potential clients to go wide-open with you. Every single thing we have talked about has now built value and price follows value. This is where we end the first meeting and I tell them that I want to review my notes and put a proposal (I never call it a "quote") together for them and that we can meet/call next. This first meeting usually ends up taking 1-1.5 hours, an initial meeting I had last week took 2. My proposals run 2+ pages. The opening paragraph is the introduction to the project and the approach- if they said they want to expand then the website "will be built with your goals for expansion in mind". The next are bullet points that now re-iterate much of what we talked about in our initial meeting (the 7 questions). Next I talk about timing, to head off "how long will it take"- that this project is a collaboration where we depend on each other to get content, approve designs, consider the features that the website is going to have, etc. We're all in this together, and I am invested in this with them. You're now thinking about their concerns before their questions and you've worked to control that conversation. If I'm asked for more detail, I say that we will set timelines for each stage when we get started- so when design starts the timeline is X, when that is approved we set the next timeline, etc. Then comes the price but I close with the terms of payment. It's usually 40% to get started, 40% on design approval when we go to code, and 20% on launch. Now the client is looking at the price in terms of affordability over the coming X amount of time. Here's what this process has done: my language says "I'm an agency" not "a person who does websites". The client has probably talked to me more than they ever have to other web people. They've shared the good and bad, we have a relationship, and now you have absolutely everything you need to do your best work and they know that. They probably also haven't encountered someone who wants the website to achieve conversions. They now know me as an expert. When you establish relationships with clients consider these items: Don't talk about other clients too much unless you're building rapport and talking about wins before they sign a contract. After that it's like a husband talking to his wife about his girlfriend. You can break this rule if you're talking about a success they've had that you want this client to have and correlate- because you're making it about the client you're talking to. Don't let a client feel like you're too busy or rushed. If an existing or past client needs help with something and it's small- consider what's worth more to you: the money you can bill, or the value of a client relationship. Only consider this if it's small and you can afford it- there is never anything wrong with billing a client. Be selective of who you do this with, don't do it often. Don't create a pattern and expectations. If you do this, be explicitly clear in an email (document it) with something like "I took care of that issue. This on is on the house so we'll skip the bill on this one. Let me know if you need anything else!" Make sure these are small, it makes a client feel like you aren't nickle and diming them. Do not overdo this. Don't do this to win over a bad client. Keep it for your best customers. Yeah, things don't always go well If you're still reading this ridiculously long post... Sh!t happens. You miss a deadline, you got a flat tire, your dog ate your homework. You misconfigured someones DNS and took their site down. Whatever. I would argue that if something goes wrong it's almost always the best opportunity to show how good you are. The only thing that people remember more than a problem is how you handled it. Be honest about it, admit fault, own it. If it was due to an error on someone else's part, I generally try to stay tame on blame and explain what went wrong rather than who did it- unless it was a) something egregious, or b) the person that did web work for them previously. You're not trying to dunk on them (be diplomatic) but you are there to solve problems and making sure they understand why you're now working with them and the other person isn't can be positive. Did a potential client reject your proposal (surely you aren't calling them quotes, right?) Try to negotiate if you're in a position to do it. If you've built value and it really does come down to cost, then look to have the value you've built help in negotiating. Etc. Random stuff I don't send invoices, my billing platform does. Built in document emailing, automated reminders for late clients, time tracking, reporting, expense tracking, customer portals, online payments through Stripe (and others), customizable branding, etc. If you don't have one, check out InvoiceNinja. It's open-source, built on Laravel, has an API, and you know how to put stuff on a web server, right? 😎 Create a subdomain like billing.yourdomain.com and it's pretty much ready to go. An update email describing less progress on a project than a client may want to hear is better than saying the same thing after they had to ask because they haven't heard from you. Keep communication open and going, let them know that you are thinking about them. Consider offering web hosting to clients when you feel like it's a good fit. Easy and inexpensive, I use StatusCake to monitor all the sites I host so I know if anything goes wrong. So my hosting is "private, exclusively for my clients, and monitored 24/7" Spin up a VPS at a reputable place. For managed hosting I use Dreamhost, for unmanaged Digital Ocean. I have a Dreamhost VPS and a separate managed MySQL DB VPS It's not really an "income source", you don't have to charge much, but it pays for all of my hosting and domain fees (including for my billing platform). They're happy, I'm happy. Very convenient to work on client sites when you don't have to juggle passwords for GoDaddy or some service they've set up. Should you be a company or a freelancer? Up to you. Historically I was a freelancer, then this year I formed an LLC. You don't have to do it but there are benefits Professional image, taxes, a more formal business interaction, legal protections Shows my clients that I'm as serious about what I do for my clients as they are. Consider creating a "marketing deck" Agencies create these to display their services and offerings. They're usually tailored to a specific client, but having a general one to provide people I'm interested in working with is a great professional document. Make it look nice, you don't have to print it, just create a PDF to have and mail. What else can you do? Can you offer more services beyond websites? I provide "web services", so design/build new websites, update/maintain/optimize existing websites Offer building integrations between platforms, provide CRM work where needed if possible Analyze business practices to help optimize workflows Research and provide recommendations for software that solves problems Help manage existing platforms, and train others to use them Think about how a developer gives you the tools for analysis, problem solving, and fast learning. You may learn software faster than other people- I've offered to learn software and then teach it to people who already use it. Think about what you can do that solves a problem while at the same time lowering the bandwidth for employees at a company. This went on waaaaay longer than I thought it would but I just shared whatever came to mind. If you are interested in seeing the deck I put together for my services (and have a reputable account with a history here in the forums) PM me. I don't want to share it in the open since it contains PII. If you found any of this useful, shout out to @kongondo for encouraging me to share. Would love to hear everyone's thoughts, critiques, and suggestions! As always, I am 100% open to being wrong about things that someone else could help me be right about.
    26 points
  38. Happy New Year! This week we've got ProcessWire 3.0.209 released on the dev branch. Consider this version a release candidate (RC1) for the master/main branch. Relative to 3.0.208, this version contains primarily issue resolutions and minor improvements (commit log). If you have a chance to test it, please let us know if you run into any major issues by reporting them here. So long as no new major issues surface, by this time next week my hope is that we'll have the dev branch merged to the master/main branch for version 3.0.210. This week one of my clients pointed me to https://chat.openai.com/ which is really quite interesting. It's an artificial intelligence that you can chat with, and it knows quite a lot about ProcessWire and how to code in ProcessWire. Though it knows a lot about a lot of different APIs, and actually a lot about everything, not just development related stuff. But I mention it here because of how it appears it's been trained fairly well in ProcessWire. When I asked it for examples of what CMSs it knows how to code for it told me WordPress, Joomla, Drupal and ProcessWire. I'd encourage you to get an OpenAI account to try it out, it can blow your mind. Ask it questions like how to develop a ProcessWire module, how to build a search engine in ProcessWire, how to use pagination in ProcessWire, or anything you can think of. It seems to have an answer for everything. The client that told me about it is currently using it to write AWS scripts for him, and he said it's saving him a lot of development time. What I also find interesting is not just how it seems to have an answer for everything, and that it knows how to code, but also that it makes mistakes pretty regularly, and recognizes those mistakes when you point them out... and apparently learns from them. That's basically how we work. For example, I asked it how to resize an image in ProcessWire and it explained through text and code examples how to use the size() method on image fields. But it also told me that I could use the $options argument to specify the type of resize interpolation (bicubic, linear, nearest, etc.) and ProcessWire has no such option. When I told it that, it apologized and corrected its code example, and also explained more details about the size() method's $options argument. There was another instance where it made a mistake (trying to do a PHP math operation within a string) and I explained that PHP doesn't support that. It essentially said "I know that, but my example doesn't do that". Then I asked it to double check its example because it didn't look right to me, and then it replied (paraphrased) "Oops, sorry, you are right, here's a corrected version." Anyway, it's just kind of funny to me that I'm talking to a computer with these kinds of interactions, and how it seems to "think" and learn a lot like we do. It will be interesting to see where this technology leads. Currently it is a free research preview, where I suppose we are helping to test the AI and help it learn, but it's very interesting and engaging just to talk with it. Also worth noting is that it does not have internet access (other than to chat with people). So it can't go and hunt down information from websites, actually making it that much more impressive in my mind.
    26 points
  39. ProcessWire 3.0.196 contains 10 minor issue fixes, but the biggest additions this week are 6 pull requests submitted from @bernhard. This most notable PR is an upgrade to AdminThemeUikit that enables greater customization of the theme's markup. If you recall, Bernhard also provided a PR last year that enables customization of the admin theme's CSS/LESS, so now he's now completed the circle and provided us with a direction for customizing the markup as well. This newest addition lets you provide your own custom render files for different parts of the admin theme by placing them in /site/templates/AdminThemeUikit/. Third party modules can also define custom render files. Furthermore, this addition adds a new hook that enables you (or your modules) to hook into and modify just about any part of the admin theme rendering. Rather than going into all the details and repeating all of the instructions here, see the new AdminThemeUikit README file "Customizing Markup" section which describes all of the different things you can modify and how to do so. You can also find all of the render files in the core AdminThemeUikit directory — any .php files beginning with an underscore are custom render files that can be overridden. While not as broad in scope, there were other useful PRs added this week as well, so be sure to see the dev branch commit log if you are interested in seeing what else was added. Thanks for reading and have a great weekend.
    26 points
  40. As we continue to work towards the next master version, this week I've been working on fixing reported issues. A new $sanitizer->words() method was also added which reduces a string to contain just words without punctuation and such. It was added in part to work on an issue reported with the tags feature in the field editor, but should be handy for other cases as well. As part of that update, the existing $sanitizer->word() (singular) method was re-written to support the features needed for the new words() plural method. This week I've also been working on a pull request from Bernhard that enables greater customization of AdminThemeUikit by way of custom render files and hooks. I'm bringing in that PR and it has a lot of good ideas that have inspired some related updates to it. I've got a bit more work and testing to do before committing, but that part should be ready early next week, along with more core updates. Thanks for reading and have a good weekend!
    26 points
  41. This week the new ProcessWire Invoices site profile has been released on GitHub here: Invoice Application Site Profile. This particular profile is much broader in scope than the others I've developed for ProcessWire, so will benefit from more descriptive information about what it includes, how to use it and modify it, and how you might build further from it. That info will all be coming next week in a new blog post. But feel free to download and install the site profile sooner if you'd like. If you are already familiar with ProcessWire, then perhaps most of it will be self explanatory. While this site profile doesn't cover everything that you might do with an invoicing application, it does cover everything that I've needed over the last year of using it with my clients. Though admittedly, I don't have a lot of clients, nor do I send a lot of invoices. Given that, when my existing invoicing service raised the monthly rate from $3/month to $20/month (a year or so ago), that's what motivated me to build this site profile. And it does everything my previous invoicing service did, and in fact does it better. While much of it was built several months ago, major improvements have been made to it over the last couple of weeks, preparing for it for release as a ProcessWire site profile. My hope is that you'll find this site profile easy to work with, and easy to build out further where needed. For instance, I imagine some may want to add in the ability to pay an invoice. It would be relatively simple to add in FormBuilder with its Stripe Processor plugin, or perhaps some other payment solution. But all my clients pay by check, whether physically or digitally, so I've not needed to add payment ability to the application yet. In any case, I hope that you find this site profile useful, and please let me know if you run into any issues with it or have suggestions for future upgrades to it. Thanks for reading and have a great weekend!
    25 points
  42. The core version has been bumped to 3.0.233 this week. While there aren't a lot of commits, there are some major updates to the core PagesVersions module. I also thought a version bump would be helpful as there's also a new PagesVersionsPro version released which requires features only available in 3.0.233. The PagesVersions module is now pretty much finished in terms of its API and feature set. This week the ability to save and restore partial versions was added, and that was the main remaining thing. By partial versions, I mean the ability to specify what fields are included when a version is saved or restored. Though I think it's primarily useful on the restore side. So if you find you just want to restore one or more particular fields from a past version, rather than all the fields, now you can. The core PageTable field was also updated to support versions, partially anyway. It supports versioning of items already in the page table, but doesn't handle versioning of items that you might add or remove within a version. It turns out it's going to be a lot of work to do that, so I settled with just partial support for this week. As it is, if you add a new item to the PageTable while in a version, then it'll ask you if you want to import it once you edit the live version. If you delete an item, it'll be deleted from all versions. That's how it works temporarily until it fully supports versions. ProFields Table now also supports versions. But there is one case where it doesn't: paginated table fields. A future version of Table will add support for that. Until then, the PagesVersionsPro module does make it clear when a paginated table field won't be added to the version. So now all fields in ProcessWire are supported, except for certain scenarios in PageTable and Table fields. A new version of the PagesVersionsPro module was released as well, and this is posted in the PagesVersionPro support board download thread here. This module made a lot of progress this week and will continue to evolve in the coming weeks. I'll copy/paste the version 2 changelog for it below this post. This weekend or early next week I also plan to release new versions of ProFields Table and Combo. These versions facilitate versions when doing partial save or restore operations that include file or image fields in Table or Combo fields. I hope that you and your family have a wonderful Winter/Christmas/Hanukkah/Festivus holiday! Version 2 changelog for PagesVersionsPro Added the ability to select which fields are included during a restore. When doing a restore, it now detects which fields differ between "live" and "version", making it easier for you to choose which fields to restore. When editing a version the “Delete” tab in the page editor now refers to deleting the version rather than trashing the page. The “compare” option has now been improved so that it can better detect differences between the live and version page. During restore, if you “Choose which fields to restore” you now have the option to compare them individually to see what is different between live and version. Added "page-edit-versions" permission so that you can limit the capabilities of this module to specific user roles.
    25 points
  43. There are a few commits on the dev branch this week, but nothing particularly notable. I had to do some client work this week but also ventured back into the Invoice site profile, which I mentioned quite awhile ago, but hadn't yet released. I'm hoping to finish that up and release it as another site profile option for ProcessWire very soon. Perhaps as soon as next week. I had originally planned on building out that Invoice site profile quite a bit more, but having used it for my own invoices for many months (maybe a year?), I think it's better to keep it simple. Otherwise I'd be making assumptions about what others might need. Even in its relatively simple state, it suits my own needs well. And I think if it gets more complex, then people are less likely to explore and modify it, making it less useful as a site profile. The site profile is also simple enough right now that it doesn't need to be a Pro module or need Pro-module support. Since we don't have a lot of site profiles to choose from, I'd rather keep it free. It is admittedly more of a mini application than a website, which is why I think it might bring some more diversity to the available site profiles. Chances are it won't replace whatever invoice service you might be using, but I think it's still pretty useful, whether using it to create invoices, or just using it to explore more of ProcessWire. More next week. Have a great weekend!
    25 points
  44. There hasn't been a lot of activity on the core this week, as I've been wrapped up in a ProcessWire-based client project (same one as last week). I'd like to put in a few more updates before bumping the version number, which will likely be next week. This week I also released a new module to accommodate a feature that had been requested more than once, but since it's not that commonly needed, I thought it was better to put it in a module rather than the core: Custom Inputfield Attributes for ProcessWire This module enhances both the interactive and API configurability of fields in ProcessWire (both admin and front-end). It can add custom attributes to Inputfields in ProcessWire, FormBuilder, or other Inputfield forms. Custom attributes can be configured interactively in the admin, or they can be added via this module’s API method. Custom attributes can be added to the <input> element of an Inputfield or they can be added to the wrapping .Inputfield element. You can add any attribute that you want (with a few exceptions), whether replacing or appending existing attributes, adding data-* attributes or any other named attribute. This module is available for download now on GitHub with more details on the module info page. Thanks for reading and have a great weekend!
    25 points
  45. ProcessWire 3.0.219 on the dev branch focuses primarily on a major overhaul to the core $modules system. The Modules class had grown into more than 5000 lines of code — all related to modules, but with lots of different areas of focus within that. It had become a little bit messy, fragile and hard to maintain at that size. I've had @todo notes in the class to "clean it up" for quite awhile, but this week I finally got to it. The approach is similar to that of our $pages API (Pages class), which is split into separate classes for page finding, loading, editing, caching, etc. The Modules class has been split into several much more focused classes for module information, installers, loaders, files, flags, duplicates, and configurations. This leaves the main Modules class as the gatekeeper, making it less fragile and easier to maintain. If this overhaul was perfect, you shouldn't notice any difference, and the public $modules API remains as before. But with such significant overhaul that took a full week to complete, there's also an increased potential for temporary errors, so please let me know if you encounter any. Thanks for reading and have a great weekend!
    25 points
  46. This week we've got a new core version on the dev branch, version 3.0.208. This version includes 15 new commits with a combination of issue resolutions and new features. See the dev branch commit log for full details. In addition, we have new versions of the following ProFields modules: FieldtypeTable, FieldtypeTextareas, FieldtypeMultiplier and FieldtypeFunctional. (Last week a new version of FieldtypeCombo was released as well). These are all posted in the ProFields downloads thread. These versions all add support for the new InputfieldTinyMCE module, in addition to other regular improvements and updates. I think that completes the list of modules I've developed that needed an update to support InputfieldTinyMCE. Speaking of InputfieldTinyMCE, it also received updates this week, primarily focused on resolving reported issues. Thanks for reading and have a great weekend!
    25 points
  47. In addition to site development work and ProcessWire core development, this week I upgraded my OS X version (from Mojave to Monterey), my PhpStorm version (from 2018 to 2022), and my Apache/PHP/MySQL environment versions. I tend to wait a bit too long between upgrades on my computer and so I ended up with a lot of things to resolve, and a still few remaining. While waiting for upgrades to install, I randomly came across one of the first sites I ever designed/developed out of college, working for Grafik in the year 2000: https://americanhistory.si.edu/subs/ ... I can't believe it's still there. It looks really dated now (it's 22 years old), but reminded me of how much things have changed in web design/development. While I'd been developing sites for a few years before this, it was just a hobby, and it wasn't until this time that it was my job. Back in 2000 there weren't a lot of people that knew how to create websites and it always felt like you were breaking new ground. Internet Explorer was king (and nobody liked it then either), Google was just a small startup, but AltaVista, InfoSeek and Yahoo were big. Sites were developed in a way that would make you cringe now. I don't think we used CSS hardly at all, but we did use tables for everything layout related. There was no such thing as "mobile" (the iPhone didn't come till 7 years later). There was no such thing as "responsive" layout and accessibility was pretty much an unknown. Most of the time we used images for a lot more than was appropriate (headlines and much more) because HTML and HTML fonts were so limited. It all seems so primitive now but what's the same is that it was fun then and it's fun now, actually it's more fun now. I don't have any point here, just that it's funny to look back at how much as changed. Last week I mentioned that we're likely to upgrade CKEditor 4 to CKEditor 5 sometime in the next year. There were several comments about that and so just wanted to talk a little more about it. First off, I really like CKEditor 4, it's been a great fit for ProcessWire. If the company behind it was going to continue building and supporting version 4 after 2023 then we'd likely stick with it. But the CKEditor 4 end-of-life is sometime in 2023 and I don't think it's an option to stick with it (in the core) after the developer of it is no longer updating or supporting it... at least not long term. While CKEditor 5 is a different animal than CKEditor 4, it's also still the closest upgrade path from CKEditor 4, and I'm hopeful it will be able to serve as a near drop-in replacement from the perspective of users (only). My hope is that by the time we've completed the upgrade to CKE 5, our clients won't necessarily know the difference or have to re-learn anything, unless they want to take advantage of something new exclusive to CKE 5. From my perspective as a developer integrating CKEditor 5 into ProcessWire, the development side is not a drop in replacement for CKE 4 (not even close), as all supporting code will have to be redeveloped. By supporting code, I mean things like the code in the InputfieldCKEditor.module file, the code for our custom CKE plugins (pwimage and pwlink), as well as anything else development related that is referring to CKEditor. There's no doubt it'll be a lot of work. But the rich text editor is one of the most important input types in the ProcessWire admin, so it's fine, it's worth putting a lot of time into. As for CKEditor 5 being bloated relative to CKEditor 4, I very much doubt that's the case. It was a complete rewrite, the folks at CKEditor know what they are doing, and it's safe to assume it's even more optimized and streamlined than CKE 4. In terms of size, the download for CKE 4 and CKE 5 are both 1.7 megabytes. As I understand it, they started with a new codebase for CKEditor 5 in part to start fresh and avoid legacy bloat. So I see this upgrade as being the opposite of bloat. So what happens with CKEditor 4 in ProcessWire when it likely is replaced with CKEditor 5? So long as CKE 5 can be a near drop in replacement for our users, and for the markup it generates, then the CKE 4 module will move out of the core and into an optional module you can install from the modules directory, when/if someone wants it. On the other hand, if the transition is not completely clean between versions then we may end up supporting both in the core for a short period of time. Though I'm hopeful this won't be necessary. There are some other interesting looking editors out there that have been mentioned, and it'd be nice to have more input options available. I see something like Imperavi's Article as a good option for some but not a replacement for our current rich text editor. At least I know my clients would not be happy to have that big of a change occur from a PW version upgrade. Likewise, something like the Easy Markdown Editor is a great option for some, and I'd like to be able to install a module for that and use it in some cases. But folks used to using CKEditor 4 in their work would not be happy to have that big of a change either. CKEditor 4 works really well for what it does, and I think the goal has to be that clients using CKEditor 4 now should be able to continue doing what they are doing with as few changes to their workflow as possible. I'm hopeful we'll be able to get there with CKEditor 5, while also gaining some benefits in the process. Where other input options make a lot of sense is when building a new site where there aren't already users depending on one input method or another. And it may be that at some point (sooner or later) it will make sense for ProcessWire to have another textarea input option that's different enough from CKE to make it worthwhile. But in my opinion, that would be a potential additional option, not a replacement, as CKE is pretty well established and expected in PW.
    25 points
  48. We had a smooth rollout of the new main/master version 3.0.200 last week (read all about it here). If you haven't upgraded yet, consider doing so, this new version is a great upgrade. I'm going to add the 3.0.200 tag shortly after I finish this post, which should trigger other services (like packagist) to upgrade. I've had a new client project in the pipeline that I've been waiting to start till the new main/master version was out, so this week I started that project. Pete and I are working together on it, like we've worked on others before. It involves taking a popular WordPress site and rebuilding it completely in ProcessWire. I've done this a couple times before, but this time it's bigger and broader in scope. I always find the large site conversions to be great learning experiences, as well as great opportunities to show how ProcessWire can achieve many things relative to WordPress, in this case. At this stage, I'm having to spend a lot of time in WordPress just to get familiar with the content, fields, etc., as well as in the theme files (php and twig). The more time I spend in these, the more excited I get about moving it into ProcessWire. For this particular site, moving from WordPress into ProcessWire is going to result in a big boost in efficiency, maintainability, and performance. Part of that is just the nature of PW relative to the nature of WP. But part of it is also that the WP version of the site is kind of a disorganized patchwork of plugins, code files, and 3rd party services, all kind of duct taped together in an undeniably confused, undisciplined and fragile manner. (Though you'd never know it by looking at the front-end of the site, which is quite nice). This has been a common theme among WordPress sites I've dug into. Though to be fair I don't think that's necessarily the fault of WordPress itself. I always enjoy taking a hodgepodge and turning it into an efficient, performant and secure ProcessWire site. I love seeing the difference it makes to clients and their future by taking something perceived as a "necessary liability to run the business", and then turning it into the most trusted asset. I think the same is true for a lot of us here. We love to develop sites because it's an opportunity to make a big difference to our clients… and it's fun. Ironically, if past history is any indicator, I seem to get the most done on the core (and modules) when I'm actively developing a site. Needs just pop up a lot more. I don't know if that'll be the case this time or not, but I do expect to have weeks with lots of core updates and some weeks with no core updates, just depending on where we are in the project. This particular project has to launch phase 1 by sometime in July, which is kind of a tight schedule, and that may slow core updates temporarily, but who knows. I'll share more on this project and what we learn in this WP-to-PW conversion in the coming weeks. Thanks for reading and have a great weekend!
    25 points
  49. I figure this is an off topic board among friends here (like our pub, or a real one) and it’s okay to write with honesty and engage in spirited or sometimes heated conversation. So just want to be clear that I like and respect @MoritzLost and value his opinions, even if I don’t agree with all of them. We will all have a diversity of views and everyone should feel free to share them, and likewise others should feel free to question those or state their own, which is what I’m trying to do. But I’m glad MoritzLost shares his opinions here. Plus, a little controversy also helps to engage the community, and drags me out of the code for a bit, so I can’t fault anyone for that. Once I can state my thoughts, I carry no concerns, but thought I should defend the things that deserved defending, as I always should. As a caretaker of this project, part of my responsibility to add my honest point of view to a conversation like this, especially when something is posted where I don’t fully agree. I think many in our community know the subjectivity of statements here (whether OP’s, mine, or another’s), but an equal number may not, as this is a public board. So some counterpoint or back-and-forth is not only clarifying to the larger audience, but also useful, as we explore different facets of it all, and lead to the most important takeaways. I appreciate that MoritzLost continues to defend his point of view on parts, despite my own defense or heated questioning of those parts. It helps me to better understand and know which are the parts that he thinks are most important and deserve the attention. We obviously don’t have the resources to pursue everything Craft does, so narrowing in on the most important parts—the meat of it—is helpful here. I’m traveling right now so can’t participate as much as I’d like to at the moment but just didn’t want MoritzLost or anyone else to think I was angry or something. Likewise I didn’t want anyone else to think they had to moderate themselves either. When I’m among friends I feel comfortable to express and be honest, and so should you. If you get a heated reply from me it’s because I care about it and value your opinion. I’ll spend more time reading everything when I get back, but I can see already it’s a good and helpful discussion.
    25 points
  50. A few weeks ago I told you about a new module I was working on that automatically saves front-end form submissions and can send email reminders for the user to finish their form. The module is called FormAutoSaver. This week I finished up that module and have released it both in the ProDevTools board and the FormBuilder board, and it's available for download now. Note that it is first release/beta test version right now. This module can be used with or without FormBuilder. Though when used with FormBuilder it is more of a turn-key setup that can be done in the admin. I've put together a dedicated FormAutoSaver documentation and information page on the site, so rather than repeating a lot of information here I'll point you to that, if you are interested in it. I also wanted to mention that a new version of FormBuilder has also been released this week (v52). There aren't any major feature additions to write about here, but there are several small improvements and bug fixes. By the way, I've added FormAutoSaver to one FormBuilder form on this site: the site submission form. There's not much to see, since it silently works in the background. But if you want to try it out, fill-in some or all of the form (making sure to fill in your email address), but don't submit the form. Feel free to leave the form or even switch devices. You should get a reminder email in 5-10 minutes with a link to finish your form. While you are there, please submit recent sites you've built in ProcessWire, we love seeing your work! My kids are starting spring break from school next week, so I'll be mostly offline and likely won't have any updates next week, but will be back to core updates after that and hopefully getting ready for a release candidate of our next master version shortly after. Thanks for reading and have a great weekend!
    25 points
×
×
  • Create New...