Leaderboard
Popular Content
Showing content with the highest reputation since 12/15/2024 in all areas
-
I’m happy to report that today the dev branch has been merged to the main/master branch with our latest version: 3.0.244. This is after about a year on the dev branch. Relative to the previous main/master version (3.0.229) there’s a lot to cover. That’s what I’ll be working on this coming week, writing a new blog post outlining all that’s new and all that’s changed. Like with most ProcessWire versions, it should be an easy upgrade, swapping out the old /wire/ directory for the new one. Thanks for reading and stay tuned for more details next week!32 points
-
The plan was to merge dev to the main branch today, but I’m still working through a couple of GitHub issues that I’d like to resolve or finish the conversation before finalizing the 3.0.244 main version. One example is this issue report where it was pointed out that there are some issues with UTF-8 page names. ProcessWire uses PHP’s IDN functions to manage conversion to and from the non UTF-8 version of the URL. PHP 7.4 changed the default arguments of the idn_* functions to settings that made them not work 100% for page names in a few cases, which I didn’t realize before this week. But this is not an issue that I can just fix and be done with it… There may already be page names in any given installation that are affected by the post PHP 7.4 behavior. If I were to just fix the issue, then some affected pages might no longer match when accessed directly by URL. So this had to be a carefully considered fix. What I ended up doing is fix it for any new PW installations that occur after this weekend. PW keeps track of its installation date, so can do this by way of its $config->installedAfter(“2025-01-05”) function. Existing installations will keep the imperfect behavior. Presumably it doesn’t affect that many installations since it only came to light last week and PHP 7.4 was released roughly 5 years ago. Nevertheless, existing installations that want the “fixed” behavior can get it by specifying this in /site/config.php: $config->pageNameWhitelist = 'v3' . $config->pageNameWhitelist; That essentially says to use version 3 of the page name conversion. Version 2 will also work fine, but may be slightly slower since it uses a dedicated Punycode library. And version 1 is the one that worked correctly until PHP 7.4, and still works mosts most of the time, but can produce imperfect results in some cases. Installations prior to 5 Jan 2025 use v1 by default and installations after 5 Jan 2025 use v3 by default. Chances are few (if any) will want to specify the version manually like above, but the option is there, just in case. That’s one example of why I’m waiting another few days before the dev branch merge to main. Another is that Adrian mentioned double-clicking on the “Move to Trash” button [in the page editor] makes it permanently delete the page rather than trash it. While I can’t duplicate that, despite multiple attempts, I just want to make sure there’s not something that needs fixing there. But unless any major new issues turn up, by this time next week we’ll merge to main and bump the version to 3.0.244. Thanks and Happy New Year!28 points
-
This week the dev branch version has been bumped up to 3.0.243. Relative to the previous, this has 30 commits, including a lot of minor issue fixes. The plan is to release the next main/master version of ProcessWire on or before New Years day. We’re down to very few new issues being reported, and even fewer resulting in code changes on the dev branch, which is a good sign the new version is ready, or very close to it. This week while working on a site I realized that the $config->maxUrlSegments setting was not working, and I don’t think it has since the PagesRequest and PagePathFinder classes were introduced into the core. So I fixed that, while also updating some of the logic around it, and adding a new $config->longUrlResponse setting that lets you specify how it should respond when it gets too many URL segments, too long of a URL, too much path depth, etc. Next week I’ll be working on updating materials related to the new version (README file, etc.) and keeping an eye out for any newly other reported issues. Thanks for reading and Merry Christmas / Happy Holidays!27 points
-
We’ve been building web site with ProcessWire since 2013. ProcessWire serves to us as a secure, reliable platform, and honestly, I don’t remember any significant issue after 11 years of daily use (for us, PW is also a CRM). The magic of ProcessWire is that it is always growing with our needs and serves any unimaginable demand that our platform has had. All these years, our business has grown around ProcessWire, and as it usually happens, popularity brings the other side of the coin. In our case, it was online fraud and scammers. Our first approach was to use existing fraud prevention systems, but as our business is not pure e-commerce and fraud was indirect, there was no solution that matched our needs, so we started developing our system from scratch. This is where I exactly understood how ProcessWire and the community really hooked me. (-: First of all, taking ProcessWire as an example, we decided not to heavily rely on frameworks. It was a hard decision, because new school engineers like to bring as many dependencies as possible, but I continuously pointed to ProcessWire, and as a result, we created a fraud prevention/user behaviour analytics platform with ~4 PHP dependencies. The second decision that we took, looking at ProcessWire, was even harder than the first. The fraud prevention market, in contrast with CRM, is not widely targeted for open source software, but taking ProcessWire as an example, we decided to open source our system after ~8,000 engineer-hours under the AGPL license. For sure, after being open-sourced for one week, it's premature to give any feedback, and it is highly possible that open sourcing was a mistake. However, it brings me to the understanding that the real measure of software is not downloads or stars, but its influence over other developers, and from them onto other developers, like ripples on the water. From this perspective, I am infinitely grateful to @ryan, @Ivan Gretsky, @Soma, and every person behind the ProcessWire community for all the inspiration through these years. I'm so grateful that 11 years ago I met this community and had the chance to work with some of you. As I'm more reader than writer, I would like to use this rare opportunity to wish the ProcessWire community and your families a Merry Christmas and all the best in the New Year! Best Alex P.S. While this post is not intended to be an advertisement, if someone from community is facing challenges related to online fraud, user spam, or security, please feel free to contact me directly.20 points
-
View website: ID Studio Web Agency We have been working on the ID Studio website for quiet some time using ProcessWire extensively for ourseleves and 90% of all our clients. This post will highlight some features we have implmented and also show off some of the hidden functionality. A quick overview is as follows: Custom web design of course 🙂 Front-end uses Canvas and Three.JS The core objective for us is to get users engaged, reviewing the showcase and services, then getting in touch The showcase and blog have alot of content We hide the ID Lab and About section in the footer but there if folks want to dive in and have the time Development features include: We use the form builder system with some custom modifications 3D tools and management Linking 3D elements to HTML elements Repeater matrix for content panels and lots more, best way is to see it on the video overview below ID-Overview.mp412 points
-
We had a chat a bit with @Ivan Gretsky and understood that probably I need to complete our story with more details. Unlike common images of start-ups, this is not fun at all. As mentioned, we developed this system bootstrapped for 1,000 days with a remote team of 11 (4 female, 7 male) from Ukraine, Georgia, Netherlands, Germany, Switzerland, Poland, and Thailand. My second son was born during this period, and I was literally working on this with a baby in one hand and a laptop in the other. We lost connection with our lead developer, as he was in Kharkiv (Ukraine). We haven’t had a connection with him since July, but I sincerely hope he is safe… If someone had told me that it would take 1,000 days (I had planned for three times less) and several thousand engineer hours, I probably would have never started this development, as it looked so unreal. It took approximately half the time to develop the system itself and another half to debug it to the condition it has now. Of course, during this development, we had to rewrite everything from nearly scratch several times, and it still doesn’t look perfect, but at some point, we understood that it is impossible to develop the code on our own and we need to share it with the community. The code release itself was quite a journey. Especially the last weeks, days, and, most difficult of all, the last hours. Arina (our junior lead developer) and me spent all day in a smoke-filled bar in Belgrade polishing the last version prior to release. And, of course, at the very last moment, we found a very unusual error that was extremely difficult to debug at 1AM. And at 6AM, I had to rush to the airport. There was a 37.5cl bottle of champagne for the three of us: myself, Arina and our director (photo attached), and despite popular images of startups, there was no party at all, only a pretty intensive and really hard time prior to release. So my advise for everyone whom working on large code base are following: - multiply every realistic time estimation for three; - have always backup for lead developer; - be ready to release the code better soon than later, as it will never be accomplished. I write this here now because I wish to learn this before starting this journey. Of-course I expect that there another bunch of rakes around that only waiting for it’s time P.S. If someone could share simple user tracking event module for ProcessWire that we can adopt for use with tirreno, it would be highly appreciated. I was not aware how stars are important for GitHub ranking, so would like kindly ask to put one if you see this software helpful: https://github.com/TirrenoTechnologies/tirreno8 points
-
Plates for ProcessWire is a module to make using Plates with your ProcessWire templates plug-and-play. Plates is an extremely lightweight pure PHP templating system that provides features that developers have come to expect when building applications and sites. From the Plates website: Highlights from the documentation: Native PHP templates, no new syntax to learn Plates is a template system, not a template language Plates encourages the use of existing PHP functions Increased code reuse with template layouts and inheritance Template folders for grouping templates into namespaces Data sharing across templates Pe-assign data to specific templates Built-in escaping helpers Easy to extend using functions and extensions Plates is an extremely stable application that has been in development and use in production since 2014. This module is also a simple adapter so I am confident in it's stability as I've already used it myself. However, the custom extensions included should be considered early releases and bug reports are welcome, pull requests are very welcome as well! If you're familiar with Plates or just want to get started now, you can download the module from the Github repository. Batteries are included, documentation provided. So, FireWire, why another templating engine? There are many stellar templating engines available. I've used several of them and they have truly great features. I also appreciate the simplicity of working with PHP. While templating engines do sometimes offer more terse syntax, it's not a killer feature for everyone like code reuse, nesting, and layouts may be. Code editors will always offer first-class support for PHP and syntax highlighting makes some of the arguments about readability less of a feature benefit for alternatives. Plates takes care of the limitations that come with writing pure PHP templates. Plates feels very at home with the ProcessWire API. Like ProcessWire, it also scales infinitely and its focus on core features over the large library approach makes for a great developer experience. If you've worked with templating engines in the past, the features are familiar. If you haven't, you'll be up to speed remarkably fast. I wrote this module with the intention of making it a "drop-in and code" experience, and I've worked on using the extensibility of Plates to add some extra superpowers to boot. Plates is another great option that may be useful to you whether because it's more your style, it fits your use case, or maybe your first time adding a little extra oomph to your ProcessWire templates. The first 10 minutes you spend with the Plates documentation might be the last 10 minutes. A Simple Example Start with files and folders. Things to know off the bat: Plates for ProcessWire comes pre-configured to look for Plates templates in your /site/templates folder By default it will look for files with the extension '.plates.php' to help differentiate from ProcessWire files, however this may be customized to any extension you prefer on the module config page The folder structure here is entirely up to you, this example can be used but is not required. /site /templates /components image_gallery.plates.php /layouts main.plates.php /views home.plates.php home.php ready.php Your ProcessWire templates will contain one line that hands off rendering to Plates <!-- /site/templates/home.php --> <?=$plates->templates->render('views/home')?> Start by creating your layout. We'll keep it simple. <?php namespace ProcessWire; // /site/templates/layouts/main.plates.php /** * @property string|null $title Page title * @property string|null $description Meta description */ $navBase = $pages->get('/'); ?> <!DOCTYPE html> <html> <head> <title><?= $title ?? $page->title; ?></title> <?php if ($description ?? null): ?> <meta name="description" content="<?=$description?>"> <?php endif ?> <link rel="stylesheet" href="<?=$config->paths->templates?>styles/app.css"> </head> <body> <header class> <img src="/path/to/logo.jpg"> <nav> <ul> <?php foreach ($navBase->children->prepend($navBase) as $navPage): ?> <li> <a href="<?=$navPage->url?>"><?=$navPage->title?></a> </li> <?php endforeach ?> </ul> </nav> </header> <section> <?= $this->section('hero'); ?> </section> <?= $this->section('content') ?> <footer> <?= $this->section('footer'); ?> </footer> <script src="/path/to/your/file.js"></script> </body> </html> I like to add docblocks at the top of my Plates templates because we can pass data to any template or layout wherever needed. This is optional and just a style preference. Some notes: The full ProcessWire API is available Your Plates templates are rendered inside a Plates Template object. To use any Plates function, custom function, or custom extension you use $this Jumping over to home.plates.php <?php namespace ProcessWire; // /site/templates/views/home.plates.php $this->layout('layouts/main', ['description' => $page->description]); ?> <?php $this->start('hero') ?> <h1><?=$page->headline?></h1> <img src="<?=$page->hero_image->url?>" alt="$page->hero_image->description"> <?php $this->end() ?> <section> some stuff here </section> <section> <?php if ($page->gallery->count()): ?> <?php $this->insert('components/image_gallery', [ 'images' => $page->gallery, 'title' => __('Image Gallery'), ]) ?> <?php endif ?> </section> <section> Some stuff there </section> <?php $this->start('footer') ?> <p>Thanks for visiting</p> <?php $this->end() ?> Things to note: The full ProcessWire API is available including language functions Even though this file is located in the 'views' subdirectory, Plates is configured out of the box to use '/site/templates/' as the base directory, so you can write paths without '../' directory traversal Plates has a feature called Folders that allow you to create namespaced directory locations at any depth with nice and clean syntax. The example packaged with the module shows a demo. We chose the main layout and passed the 'description' variable which is available in main.plates.php as $description $this->start('hero') and $this->stop() capture what is output to those sections in main.plates.php, there is no limit on sections and they can have any name aside from 'content' which is reserved. Any content that exists outside of a defined start/stop section is automatically output to the 'content' section in your layout And the image gallery: <?php namespace ProcessWire; // /site/templates/components/image_gallery.plates.php /** * @property string|null $title Optional gallery title * @property Pageimages $images Images field */ ?> <div> <?php if ($title ?? null): ?> <?=$this->batch($title, 'strtolower|ucfirst')?> <?php endif ?> <ul> <?php foreach ($images as $image): ?> <li> <img src="<?=$image->url?>" alt="<?=$image->description?>"> </li> <?php endforeach ?> </ul> </div> Some more notes: You can use $this->insert() in any Plates file, including layouts. You can also nest using $this->insert() recursively and nest in other component-style files Any template can have a layout and you can nest layouts. So home.plates.php could use main.plates.php as its layout, and main.plates.php could use something like base.plates.php so layouts themselves can share code through inheritance. You can use batch() to execute multiple functions on a value. Any PHP function that accepts one argument (or one argument and the rest optional) can be chained in a batch. This also works with custom functions and Extension functions where you can do some really neat stuff. This is similar to functions and filters in other templating engines. The Syntax The syntax, like ProcessWire, is just PHP and has complementary style and a simple API. Plates only makes style recommendations. One of the key elements to making templates in any engine work is knowing where to put logic and where control structures should do the heavy lifting. With PageClasses and organized code, templates can be clean and concise with just PHP. At it's core, Plates primarily keeps focus on templates which makes it different than other engines that tend to include new syntax and tools because they already have to build a parser or interpreter. The batch() function covers a most use cases and is a welcome tool to use as is or as a complement to more custom functions and extensions. That's all you need to get started using Plates for ProcessWire. I highly recommend reviewing the short documentation to get the most out of templates in your projects. Layouts - A core templating feature for sharing page designs and base code between templates Nesting - Enhanced code reusability by inserting code blocks Inheritance - Use code sharing between templates to build more complex designs with simplicity Functions - Batching functions and writing your own Plates for ProcessWire comes with several custom build extensions for this module that may be useful. All extensions are optional and disabled by default. You can start building with the core Plates system. Extras: Plates for ProcessWire Extensions This module comes with several optional extensions that add useful tools for building templates. Many also provide some parity with other templating solutions. All custom extensions are optional and can be enabled/disabled on the module config page. Plates for ProcessWire extensions provide over 100 custom functions to use in your templates. Many of them are batchable, many of them are written to use with ProcessWire objects such as Page and WireArray/PageArray. Others are intended to make template code shorter and cleaner, others are just nice to have. The Conditionals Extension brings some nice to have utilities. <!-- From our example above --> <?php if ($page->gallery->count()): ?> <?php $this->insert('components/image_gallery', [ 'images' => $page->gallery, 'title' => __('Image Gallery'), ]) ?> <?php endif ?> <!-- Consider this instead --> <?php $this->insertIf('components/image_gallery', $page->gallery->count(), [ 'images' => $page->gallery, 'title' => __('Image Gallery'), ]) ?> Tidy up single line outputs <!-- Instead of this --> <?php if ($page->text_field): ?> <h2><?=$page->text_field?></h2> <?php endif ?> <!-- Consider this --> <?=$this->if($page->text_field, "<h2>{$page->text_field}</h2>")?> Use match instead of long if/elseif/else chains, or matchTrue for more complex conditions <h2> <?=$this->match($weather, [ 'sunny' => __('Grab your sunglasses'), 'cold' => __('Wear a coat'), 'rainy' => __('Bring an umbrella'), ])?> </h2> <h2> <?=$this->matchTrue([ __('Tickets are available') => $ticketCount > 10, __('Hurry, tickets are almost sold out') => $ticketCount > 1, __('Sold Out') => true, ])?> </h2> The Functions Extension provides a wide array of flexible and batchable functions <!-- Get the sum of all items in a WireArray/PageArray, associative array, or object by field/key/property, Also works on indexed arrays --> <p>Total: <?=$this->sum($page->cart_items, 'price')?></p> <!-- Group items in an associative array, array of objects, or WireArray/PageArray by property or field --> <?php foreach ($this->group($pages->get('template=players'), 'team_name')) as $teamName => $players): ?> <h2><?=$teamName?></h2> <ul> <?php foreach ($players as $player): ?> <li> <?=$player->title?><br> <?=$player->position?> </li> <?php endforeach ?> </ul> <?php endforeach ?> <!-- Get PageArrays inclusive of their parent using withChildren() Assign attributes/values if a page matches the current page using attrIfPage() withChildren() accepts a Page, selector, page ID. A second selector can be passed to filter child pages --> <nav> <ul> <?php foreach ($this->withChildren('/') as $navItem): ?> <li<?=$this->attrIfPage($navItem, 'class', 'active')?>> <a href="<?=$navItem->url?>"> <?=$navItem->title?> </a> </li> <?php endforeach ?> </ul> </nav> <!-- Generate an unordered list of breadcrumbs --> <?=$this->breadcrumbs(['startPage' => '/', 'separator' => ' | ', 'ulClass' => 'breadcrumb-nav'])?> <!-- Create an indexed array with iterator from index 1 on any iterable object --> <?php foreach ($this->batch($page->images, 'toList|from1') as $i => $image): ?> <img src="<?=$image->url?>" alt="<?=$image->description?>" data-slide-index="<?=$i?>"> <?php endforeach ?> The configurable Asset Loader extension lets you link, inline, and preload assets with automatic cache busting version parameters. Directories and namespaces are yours to choose. <?=$this->preloadAssets([ 'fonts::ProximaNova.woff2', 'fonts::ProximaNovaLight.woff2', ])?> <?=$this->preloadAsset('js::app.js')?> <?=$this->linkAsset('styles::app.css')?> <?=$this->inlineAsset('styles::critical.css')?> <?=$this->linkAsset('js::app.js')?> There are more extensions and a lot more functions, with documentation. Many functions that work with arrays also work with WireArray and WireArray derived objects making them batchable. If you're a RockPageBuilder rockstar, check out the README file for details on how to use an included utility function to make Plates and RPB work together 👍 Try It Out! If you want to give it a try, download the module from the Github repository and take it for a spin. When it gets a little more testing I may submit it to the modules directory. I'm a consistent user of plain PHP, Latte, and Blade for templating and I think Plates is a great addition to the developer toolbox. Interested to hear your thoughts.7 points
-
Congrats @ryan and thank you @matjazp for helping with all the github issues! Great achievement and great start into the new year 🚀🥳6 points
-
Happy new year everyone! I've been working on adding multiple tab support for the console panel. It works in conjunction with the snippets panel so you can load up multiple snippets, or create any number of temporary (unsaved) tabs of code. Each tab has its own execution history stack and the last result for each tab is also maintained so you can flip between tabs to see the differences between results. It automatically names tabs like a typical code editor does: Untitled-1 initially, and then using the first line of code. Of course when you save the tab to a snippet, the tab name will be that of the snippet filename saved to disk. I'll push it live soon, but if anyone sees this and would like to test and provide feedback beforehand, please take a look at this branch: https://github.com/adrianbj/TracyDebugger/tree/console-tabs Thanks!6 points
-
@ryan and @ all of those reading this... https://hugerte.org/ "We've forked the last MIT-licensed commit of the popular TinyMCE WYSIWYG editor as they switched to a GPL-or-pay license model and we want to keep it free for everyone. We're working at improving the codebase, adding new features and fixing bugs"6 points
-
Thanks, @Ivan Gretsky. I wasn't sure whether the community guidelines allowed sharing links. There's a publicly available online demo for anyone who doesn't want to mess with the codebase themselves. Online demo: https://play.tirreno.com/ (Login: admin/tirreno) You can find Tirreno's source code on GitHub. It needs PHP 8 and PostgreSQL and should normally work after a short installation, which was also inspired by ProcessWire. Source code: https://github.com/tirrenotechnologies/tirreno/ By the way, if you see the Frogger game, something didn't go quite right! Game: https://play.tirreno.com/game/ Enjoy!6 points
-
@FireWire @Jonathan Lahijani @gebeer I've created a demo module that shows how to use the new config migrations. Please note that it needs the latest RockMigrations version from the dev branch! https://github.com/baumrock/ConfigMigrationsDemo5 points
-
Ever wondered when certain hooks get executed? Which hooks got fired along the request? Open /wire/core/WireHooks.php, find the method "runHooks" and paste this at the very top of this method: $logfile = wire()->config->paths->root . 'hooks.txt'; $tooOld = is_file($logfile) && filemtime($logfile) < time() - 5; if ($tooOld) unlink($logfile); $logData = get_class($object) . "::$method\n"; file_put_contents($logfile, $logData, FILE_APPEND); This will write a log of all hookable methods to hooks.txt and it will probably begin like this: ProcessWire\FileCompiler::compile ProcessWire\FileCompiler::compile ProcessWire\FileCompiler::compile ProcessWire\FileCompiler::compile ProcessWire\Fields::load ProcessWire\Fieldgroups::load ProcessWire\Templates::load ProcessWire\Fieldgroup::setQuietly ProcessWire\Fieldgroup::callUnknown (maaaany more lines) And it will most likely end with "ProcessWire\ProcessWire::finished" 🙂 Now you can play around with this logfile and view different pages. For example when opening a page for editing you will have a portion of this in the log (ProcessPageEdit::buildForm...): ProcessWire\ProcessPageEdit::breadcrumb ProcessWire\JqueryCore::use ProcessWire\JqueryUI::use ProcessWire\ProcessPageEdit::execute ProcessWire\HutPage::setEditor ProcessWire\ProcessPageEdit::buildForm ProcessWire\ProcessPageEdit::buildFormContent ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::changed ProcessWire\Field::changed ProcessWire\Field::getInputfield ProcessWire\Field::changed ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\HutPage::viewable ProcessWire\Pages::find ProcessWire\PageFinder::find ProcessWire\PageFinder::getQuery ProcessWire\HutPage::addable ProcessWire\ProcessPageEdit::buildFormChildren ProcessWire\WireInputData::int ProcessWire\WireInputData::callUnknown ProcessWire\WireInputData::int ProcessWire\WireInputData::callUnknown You can also use grep to find the hooks you are looking for, for example: cat hooks.txt | grep ProcessWire:: ProcessWire\ProcessWire::init ProcessWire\ProcessWire::ready ProcessWire\ProcessWire::finished ProcessWire\ProcessWire::finished This has helped me today to find the correct spot to hook into. Maybe it also helps anyone else. Have fun! PS: Don't forget to remove this once you are done with inspecting, of course!5 points
-
As of today we count 951 stars on Github. Would be great to hit 1k by the end of this year! I'll suggest we all invite our PW-friends to star the repo if they haven't done yet! My next newsletter will be in 2025, but I'll add it there as well. Also @teppo you might want to mention this in your newsletter which would have a lot more impact than mine I guess 😄5 points
-
Season's greetings ProcessWirers. My gift to you is a new module called PipeEmailToPage which you can get from GitHub here: https://github.com/MetaTunes/PipeEmailToPage/tree/main. Fairly 'alpha' at the moment, but I have been using it successfully on a live site for a week or so. I'll test it some more before releasing it to the modules library. I designed this as a replacement for ProcessEmailToPage, which relies on the flourish library which is no longer maintained. It also has a fundamentally different method of operation in that it is 'push' rather than 'pull'. The email addresses are created 'virtually' in the sense that they are not necessarily real email addresses but are held in pages whose templates are linked in the module config. The module works when emails are piped to a script (emailpipe.php) on the server which processes the email and creates the page. The pipe needs to be defined in your hosting service's cPanel or similar. If you define the pipe in the 'Default address' in cPanel, all emails sent to the domain will be processed unless they are specified separately. The 'to' addresses will be matched against the email addresses defined in 'parent' pages holding the virtual addresses. If you define the pipe for a specific email address, only emails sent to that address will be processed (but you can define the same pipe for multiple addresses). A major advantage of the module is that the email addresses can be defined entirely within PW. This means that they can be maintained by someone with no access to cPanel once the developer has set up the pipe. Further details are in the readme. I suggest you test thoroughly before using (and take careful note of the 'points to note' in the readme). Turn on some of the logging statements if you wish. Also, check your mail delivery in cPanel to look for errors there. If you report errors to me, I will do my best to hunt them, but please include as much info as possible. I will also be grateful for any suggested code improvements and/or PRs. 🎄5 points
-
There have been a few small bug fixes made to the core this week on the dev branch. I think we’re really close on the new version and hope to have that ready around the upcoming holidays. The module I mentioned last week (InputfieldSmallSelectMultiple) also got a new version this week with support for optgroups, support for “1 of 3 selected” type labels (Adrian’s suggestion) and a couple small fixes. Some fun news: The ProcessWire site is currently going through a redesign. This time there are a couple of professional designers and long time ProcessWire users collaborating on the design. I won’t mention who’s working on this just yet, as I’ve not asked them if I could, so want to respect their privacy. But I’ve been able to see some of the work in progress, and it’s really fantastic, a major upgrade for the look of the site. Along with this will be some visual improvements to the admin theme as well, which will accompany or come after the site redesign. There’s no launch date for the site redesign just yet, I wanted to let you know it was in progress and looking great, something to look forward to for sure. Thanks and have a great weekend!5 points
-
@artfulrobot @ryan - I wonder if some of the new techniques described here would help?4 points
-
Croatian language pack (based on PW master version 3.0.229): https://github.com/MoebiusHr/ProcessWire-Croatian-Language-Pack It is not excluded that there are minor clumsiness in the translation due to the specificity of the language and that some words are deliberately untranslated because the original English technical terms are too rooted in Croatian speech and writing. Long live PW ...3 points
-
@zilli Some great questions! I spent many years writing vanilla PHP template markup. For Occam's Razor, have the leeway to apply as many or few features a tool offers. Your mentioning Markup Regions is a good example, I use many features of ProcessWire but have never used Markup Regions (I have no opinion, it just coincidentally never became part of my workflow). Both MR and templating engines aim to overcome challenges introduced when using PHP (like any language) alone for output. So it's up to the preference of the developer and needs of a project, a la "there are no wrong answers". My limited experience with MR make me a less than ideal candidate to draw comparisons or speak to compatibility. My first thought it to flip the question of complexity and see how it applies to tools you/me/we may already use. Page Classes are a layer of complexity to abstract logic out of presentation, ProcessWire itself is a layer of complexity to abstract database transactions/data management. Templating strategies are a layer of complexity that make your workflow less complex. Tools like MR and templating packages do that as well while sometimes affording some extra tools. My experience with templating solutions was born out of bumping my head on limitations and moments of thinking "there has to be a better way to do this". I ended up using creative tricks to make 'require' and 'require_once' carry the load but ended up making my code harder to manage, more files to make it work, and felt like I was breaking good practice rules. Consider this simple example: <!-- /site/templates/inc/header.inc.php --> <!DOCTYPE html> <html lang="en"> <head> <title><?=$page->title?></title> <?php if ($includeGoogleAnalytics ?? false): ?> <?php require_once '/path/to/google_analytics.inc.php' ?> <!-- GA code here --> <?php endif ?> </head> <body id="$pageId" class="<?=$pageClass?>"> <header> <img src="/path/to/logo.png"> <h1><?=$headline?></h1> </header> Then I have my home.php and to make this work, I have to start setting big scope variables to be made available to the 'require_once' code. This got worse as the site needed more features and the header and footer became more complex. Later I had to create a new headers for other parts of the site, so multiply the code above a few more times, and add some more 'require_once' lines to each of them. <?php namespace ProcessWire; // /site/templates/home.php $pageId = 'stuff-here'; $pageClass = 'stuff-there'; $includeGoogleAnalytics = true; require_once __DIR__ . 'partials/header.inc.php'; ?> <!-- We haven't even added one line of markup/code for the home page --> <?php $includeCallToAction = true; $includeTestimonials = false; $anotherOne = true; $iHearYouLikeOutOfScopeVariables = false; require_once __DIR__ . 'partials/footer.inc.php'; ?> Here's an actual snippet from a site I build years ago. If you look at a partial or component and it has a lot of if statements, sometimes but not always, it says "I'm a file that does too much" and it becomes increasingly difficult to manage. <!-- Real snippet of production code from /site/templates/partials/footer.inc.php --> <?php if ($mainNav): ?> <?php require_once __DIR__ . '/../inc/site_nav_overlay.inc.php' ?> <?php endif ?> <?php if ($salesCtaModal): ?> <?php require_once __DIR__ . '/../inc/cta_sales_quote_modal.inc.php' ?> <?php endif ?> <?php if ($solarCleaningCtaModal): ?> <?php require_once __DIR__ . '/../inc/cta_solar_cleaning_modal.inc.php' ?> <?php endif ?> <?php if ($solarRepairCtaModal): ?> <?php require_once __DIR__ . '/../inc/cta_solar_repair_modal.inc.php' ?> <?php endif ?> Is this how everyone does it? Maybe not, hopefully not, but every project runs the risk of becoming Frankenstein's monster. With a templating solution approach this would have been solved with 4 files. You can significantly reduce the number of if statements because each of these have a job to do, they know what it is, and when you're maintaining the site, or adding new features, there is zero confusion about where to go. Working on the blog parts? Go edit the blog templates and blog layout. The service/maintenance pages know they'll need the "cleaning" and "solar repair" modals so that whole if block doesn't exist anymore. Cake. <?php namespace ProcessWire; // This is the base layout. The layouts below declare this as *their* layout and pass data if needed $this->layout('layouts/base'); // For the majority of pages on the site $this->layout('layouts/main'); // For the pages dedicated to customer service and maintenance rather than sales $this->layout('layouts/service_mainenance'); // For all blog and blog related pages $this->layout('layouts/blog'); ?> Long story short, the complexity would have been immediately reduced by introducing a templating tool with a predictable set of features and functions to use. To contrast, as a longtime user of preprocessors myself, I can say that those have the potential to introduce a lot of things that fundamentally change how you work with the language itself. Sass/Less bring nesting, loops, variables (before custom properties were available), mixins, includes, file imports, modifier functions, if/else control flows, custom functions, (the list goes on) and an entire JavaScript toolset to handle it. You can solve a lot of problems you don't have! This isn't an argument against preprocessors, but there is a higher level of discipline you must have to keep this from going off the rails and being so clever you outsmart yourself. On the other hand, templating is so incredibly fundamental to producing apps and websites that the constrains start to tighten much sooner and it becomes more clear how many workarounds and "bending the rules" of good practice are present. The benefits of introducing templating tools bring a higher number of benefits that are more impactful faster. You're also adopting a common development practice, so it is leveling up your skillset. I have to mention that these benefits are not unique to Plates. Layouts, and enhanced insert/include features, are common to pretty much all templating tools. Pick the one that feels right be it Latte, Twig, Smarty, or Plates. My only argument in favor of Plates is that if templating is something that you're introducing into your projects for the first time you may be up to speed faster because: a) the core features set of Plates is very limited (intentionally), and b) it's the same PHP syntax you already use. The concepts and strategy you use with Plates will translate to other templating tools. In the case of this module, the potential amount of complexity is almost entirely due to the custom extensions I built which is why they are optional and disabled by default. You can safely ignore everything in my post above from "Plates for ProcessWIre Extensions" on down and still get simple yet powerful tools. If you have any Q's, post them here.3 points
-
3 points
-
@joe_g It’s a bit of a late reply, but I pushed an update for the module which allows to extract the footnotes across all fields where the textformatter is applied to then output them wherever. Please have a look at the first post in the thread for an example.3 points
-
I'm loving config migrations more and more 🥰 They reduce complexity and increase stability and performance. Win-Win! Wherever you want. Nothing changed here. You can put it in /site/migrate.php, you can put it in your /site/modules/Site/Site.module.php module's migrate() method, etc... I have to correct myself here @Jonathan Lahijani Today I had to create the following page reference field: <?php return [ 'type' => 'page', 'parent_id' => '/tags/', // ... ]; The "parent_id" setting caused a problem, because the /tags page did not exist when this was run, so the migration failed. I went ahead and implemented a way to properly, reliably and easily create new pages with your config migrations: MAY I INTRODUCE: Config Migration Hooks 😍 😎 🚀 Please check out the dedicated docs page, which are at the moment only on the dev branch and will soon be merged to main and then be also available on my website: https://github.com/baumrock/RockMigrations/tree/dev/docs/config-migrations-hooks3 points
-
ProcessWire should soon be listed under the DDEV Quickstart List: List: https://ddev.readthedocs.io/en/stable/users/quickstart/ PR: https://github.com/ddev/ddev/pull/68793 points
-
FrontendLoginRegister module is updated now (Version 1.3.6) The following last 2 issues have been fixed now: Support for usage of multilanguage fields inside user template added New configuration field to make the "Request deletion of user account page" public viewable added Screenshot of the new configuration field to change the access of the user account deletion page: In the middle you can see the "Allow public deletion of a user account" checkbox. If you check this checkbox, the deletion page will be public reachable. For more information check the changelog.md. Please keep in mind! This module is Beta stage, so it is not recommended to update live sites without testing it locally before! I have tested various scenarious, but I cannot test all possible cases - so happy testing 😉 As always, please report any issues here or on GitHub.3 points
-
The following issues should be solved now: The position of the privacy check is now always at the bottom, regardless of the use of a CAPTCHA (bug fixed) New configuration field to select whether to use an internal or external page for the privacy policy added. This configuration supports multilingualism, which means you can select a different page for each language. These issues have been fixed in the FrontenForms module and not in the FrontendLoginRegister module. This means that you will need to update the FrontendForms module to the latest version 2.2.27 to fix these issues. The other problems (public deletion link, multilanguage user fields) directly affect the FrontendLoginRegister module and must be solved there. I will try to solve these issues in the next time. You can read the full documentation of changes in the changelog.md. Hope it works now as expected without problems!!3 points
-
Hi @bernhard, in the docs-old folder of the module there is a nice section about prices. It says that we can switch to gross prices with a config setting. I was not so sure whether that still applies and how it works with the cart calculations. So I just wanted to share my custom implementation, so that editors can enter gross price and net price will be calculated. I added a field (type RockMoney) "price_gross" in addition to the "rockcommerce_net" field to my product template. And in my ProductPage class, I have a saveReady hook that calculates the net price from the gross price and the vat for that product. /** * Calculates the taxrate of the product * based on the taxrate field of the product * if no custom taxrate is set, the global taxrate is used * * @return float */ public function getTaxrate(): float { return (float) $this->rockcommerce_taxrate ? $this->rockcommerce_taxrate/100 : $this->taxrate(); } /** * Executes when the page is ready to be saved. * * Only executes if price_gross is given and field rockcommerce_net is present. * Calculates the net price and VAT based on the gross price * and tax rate, if a gross price is provided. * It saves the net price to rockcommerce_net. * * @return void */ public function onSaveReady(): void { // only execute if we have price_gross if ($this->price_gross && $this->template->hasField('rockcommerce_net')) { // take price_gross and calculate vat and net price from it using taxrate $taxrate = $this->getTaxrate(); $vat = rockmoney()->parse($this->price_gross)->times($taxrate / (1 + $taxrate)); /** @var \RockMoney\Money */ $priceNet = rockmoney()->parse($this->price_gross)->minus($vat); $this->rockcommerce_net = $priceNet->getFloat(); } } I also use a custom getTaxrate() method from my page class, in case a custom rate is set for that product. Page edit screen3 points
-
Not sure if/how this applies to us. https://thehackernews.com/2024/12/new-glutton-malware-exploits-popular.html3 points
-
@ryanThanks for the incredible job you do! Merry Christmas to you and the whole Processwire community. Bernhard3 points
-
Sounds like a new module coming. RockEstimator. 😁3 points
-
Solution is here: https://processwire.com/modules/search-engine/ // Alternatively index just a single page (passing in a Page object): $modules->get('SearchEngine')->indexPage($page);3 points
-
You are indexing all the site pages every time a page is saved. You should index only this page since the work for other ones was already done.3 points
-
Thank you very much for your advice! I have indeed found a hook that was apparently to blame. I can't remember exactly why I added it and what it does ... $wire->addHookAfter('Pages::saveReady', function($event) { $event->modules->get('SearchEngine')->indexPages(); $page = $event->arguments(0); $event->wire('log')->save('Page saved', "Page ID: $page->id / Page Name: $page->name / Page Parents: $page->parents"); });3 points
-
@Alpine418 In PHP, classes are loaded with an autoloader that you can manage via composer (this is the common way). And ProcessWire comes with a composer.json file that you just have to edit, for example I edited mine like this: "autoload": { "files": [ "wire/core/ProcessWire.php" ], "psr-4": { "Rfro\\Rfrorga\\ProcessWire\\": "site/templates/", "ProcessWire\\": "site/classes/", "Rfro\\Rfrorga\\WebApi\\": "webApi/", "Rfro\\Rfrorga\\Cron\\": "cron/" } }, Now I can use any of this namespaces everywhere. In my custom classes I use base classes and traits located in site\templates\Php\CustomPage\Page\.3 points
-
->find() checks the access control/page status (contrary to ->get()) and repeater templates are hidden to guest users. Just add "include=all" to your selector and it should work.3 points
-
Yes! Either in the TinyMCE module settings, or in each field there are options for overriding the json config of the TinyMCE instance, and you can do sth like: site/templates/assets/tiny.css is my custom css file. In all fairness, I have only tested this in the global module config, not in the individual field context.3 points
-
Hello, Because I was in need of such a thing but there was nothing that I could find, I had to create my own. I'm sharing here, so maybe someone will find it useful. My second module, Use at your own risk, there may be some mistakes, please if you find them, let me know! Right now the module mostly works with datetime field!!! This was what I was going for actualy. Description Page Automation Module for ProcessWire Description: The Page Automation module automates various page management tasks in ProcessWire, such as copying, cloning, deleting, publishing, hiding, and more based on predefined conditions. It allows users to set triggers based on a page's field values and perform automated actions without manual intervention. The module integrates with LazyCron for scheduling periodic checks. Key Features: Perform actions like copy, clone, delete, publish, hide/unhide automatically. Configure conditions based on date/time fields (e.g., "older than 1 day"). Schedule actions with flexible cron intervals (every minute, hour, day, week, or year). Supports applying actions only to pages using specific templates. Option to assign a different template to cloned/copied pages. Logs all automated actions for easy tracking. Requirements: ProcessWire 3.x or later. LazyCron Module (it won't work without it). Setup Instructions: Install the module through the ProcessWire admin Modules upload by File upload. Configure the conditions, templates, and actions via the module settings. (Optional) Install LazyCron for time-based automation. Verify that the automation_processed checkbox field is automatically created for tracking processed pages. Once configured, the module will automatically handle repetitive page management tasks based on your specified conditions, saving time and effort. Important! Uppon install the module will create a new field "automation_processed" which you must add to the main template (template for action or make it global), if not you'll end up with a bunch of copies. This field tells the module that the page was already proccessed, so it will leave it alone. PageAutomation_preview.mp4 I hope u like it 😉 You can download it here: PageAutomation.zip3 points
-
Hello ProcessWire Community! I'm thrilled to announce that RockCommerce has finally arrived! Some years ago, after building a custom shop solution, I swore I would never create another ecommerce system again. 😅 Yet here we are! After months of hard work and completely rethinking my approach, I'm confident RockCommerce will be a game-changer for ProcessWire ecommerce. I can't wait to see what you'll create with it! 🚀 This video guides you through the Quickstart Tutorial, which was written by @Sanyaissues (THANK YOU SO MUCH!!!) He rose his hand when I asked for beta-testers 💪😎 He had never done E-Commerce before and wanted to understand how it works - so I sent him a copy of RockCommerce and let him play and this is what he came up with!!! Absolutely remarkable! Hat off to him! Docs & Download: https://www.baumrock.com/rockcommerce P.S.: To celebrate the RockCommerce release, I've applied discounts to all module licenses in my shop! If you've had a successful year, this is a great opportunity to invest in yourself and potentially reduce your taxes 😉2 points
-
Hey @Frank Vèssia thx for your questions! Thx 🙂 That's already built in (or possible)! I have added this to the docs for you: https://www.baumrock.com/en/processwire/modules/rockcommerce/docs/shipping/ Does that help? I've also added docs for this: https://www.baumrock.com/en/processwire/modules/rockcommerce/docs/coupons/ I've also added a section about this to the cart docs! Like all the other mentioned puzzle pieces this can mean so many things. One might want to manage users via ProcessWire. One might want to sync users with a 3rd party tool. One might want to show custom dashboards to users on the frontend. One might want to show a dashboard in the PW backend... I'm not sure how to proceed with this to be honest. RockGrid can be a great way to quickly create excel-like lists, which could also be great for managing RockCommerce users. But I'm not sure how much this would really belong to RockCommerce. It might be more related to RockGrid. Then you might want to send out invoices. That could be done with RockPdf. But you might also want to make those invoices editable, and then RockPdf does not help you. Managing invoice items alone can be a pain. A simple solution could be to use repeaters, but you'll quickly realise that the UI is less than ideal. Prices do not update automatically, so you always need to save the page - to just name one problem. I'd much more prefer having something like RockInvoice for that. With my initial version of RockCommerce that I'm using for my clients on my website baumrock.com has invoices built in. But then I wanted to use these invoicing capabilities also for my other clients that did not purchase modules from my store but ordered a website or website maintenance service. So for the customer part the short answer is yes, I think I'll leave that up to the developer. The ProcessWire way... Unless anybody has good reasons and ideas to approach it differently? But what you get out of the box when using RockCommerce is order management. At the moment this is just a list of pages in the page tree, but I plan to expand on this by adding a Dashboard that shows revenue stats and that shows a nice list (RockGrid again) of all the orders with hopefully helpful data (like who ordered, when, etc). Any input or questions are welcome.2 points
-
Merry Christmas all! A new version in time for New Years? Now there's a great way to kick off 2025 😎2 points
-
This looks really useful, by the way! Accessibility: I was going to submit this as an issue but perhaps you'd prefer discussion here as a precursor? Browser-native selects have a cool feature: you can type the label to find an item. If you're able to use a mouse like I am then this is just an efficiency, but if you can only use keyboard navigation then this is really very valuable to usability (on a long list) and to efficiency (on a short list). e.g. consider a list of countries. ("Where have you been on holiday?"). having to scroll and click is going to be awkward and slow; being able to type Uni and jump to United Arab Emirates (and below it United Kingdom) makes it a breeze. This important accessibility function gets broken by the way the icons representing selected/not are inserted as text before the labels. Sadly, CSS cannot rescue this - if CSS were supported better for <selects> then we could do various things to improve UX for visual users without it being at the expense of less able users. What about instead of using visual characters for selected/not, using <optgroup label="Selected"> and <optgroup label="Unselected"> and grouping the selected items first?2 points
-
2 points
-
Hey @FireWire thx for your report! Good news 🙂 This should be fixed in v1.4.32 points
-
The issue was that I was using Xdebug 3.4.0. When I downgraded to Xdebug 3.3.2 it started working like before.2 points
-
Thanks for an interesting perspective and for the commendation @Alexander! As you already mentioned your new open source thing, expand on it for everybody. We are in the Pub anyway))2 points
-
Happy to hear you found the issue. 😀 You could consider indexing the pages with a Lazy Cron or a cronjob.2 points
-
At first I used regions, then markup regions, and I found that I wasn't happy about performances. I did some benchmarks and noticed that the time consumed to render the page was growing faster than the amount of data to render. For example, if I double the data, rendering may take 3x the time (just a random number, I don't remember values, but I think I saved them in a text file). That's why I switched to Twig, Twig is slower for small content but is robust with big content. And I like how it's easy with Twig to write clean readable code, reuse twig fragments several times, import, extend, include, embed... there's a lot of choice, and no performance issue when including twigs into twigs. For very small html snippets that I use everywhere in the site, and are closely related to a page/template, I also have a method on my custom page classes, that calls a "Renderer" instance associated with this page and print some HTML. I use it for example for the user cards that are displayed on almost all pages of the previous site I did: <div>{{user.renderer('card')}}</div>2 points
-
Hello and welcome to processwire! The short answer is there is no recommended way. Processwire leaves that completely open to the user. Some like markup regions, I don't. Some use template engines like latte or twig, others don't.2 points
-
Also, it would be nice to fix the softaculous text to not say "ProcessWire is a free PHP5 content management system and framework ". That is a bit of a turn-off.2 points
-
Great news about the site redesign. We all know how beautiful ProcessWire is at its core (great api, great extendability, and great developer experience overall). I hope that the redesign will set our beloved CMS on par with some of its competitors as long as marketing is concerned.2 points
-
I totally get where you’re coming from and appreciate your support for open-source values. Personally, I keep renewing my Pro module membership even when I don’t need the new features. For me, it’s a way to back Ryan for all the amazing work he does. Plus, having access to support has been a lifesaver a few times when the forum couldn’t help. Maybe reach out to Ryan directly through the ProcessWire website to see if there’s a way to donate. I’m sure any support would go a long way for the project! Another idea could be setting up something like a Patreon or similar platform where the community could collectively fund updates to specific modules or even new features that aren’t currently on the ProcessWire roadmap. That might be a cool way for everyone to contribute in a more focused way!2 points