Leaderboard
Popular Content
Showing content with the highest reputation since 11/19/2025 in all areas
-
Nested Checkboxes An inputfield for Page Reference fields that groups options by their parent page, and optionally by grandparent page too. This can help editors understand the grouping of the selectable pages, and also makes it quicker for an editor to select or unselect an entire group of pages. The checkboxes at the parent and grandparent level are not for storing those pages in the field value - only for quickly selecting or unselecting groups of pages at the lowest level of the hierarchy. For example, in the screen recording above the "Cities" Page Reference field allows only pages with the "city" template, and the pages at the country and continent level are not included in the field value. The inputfield is only for use with Page Reference fields because the structure comes from the page tree. Requires PW >= v3.0.248. Configuration For each field that uses the inputfield you have these options: Checkboxes structure: choose "Parents" or "Parents and grandparents". Collapse sections that contain no checked checkboxes: this option makes the inputfield more compact. There are also the standard column width and column quantity options familiar from the InputfieldCheckboxes inputfield. These apply to the selectable pages at the lowest level of the hierarchy, and the structure is arguably more readable when these are left at their defaults. https://github.com/Toutouwai/InputfieldNestedCheckboxes https://processwire.com/modules/inputfield-nested-checkboxes/21 points
-
Hello ! 👋 I'm excited to share WireWall, a comprehensive security firewall module I've been developing for ProcessWire. After months of real-world testing on production sites (including blocking 99.98% of malicious traffic on my e-commerce platform), I'm ready to release it to the community. What is WireWall? WireWall is a ProcessWire-native security module that provides enterprise-grade protection with granular geographic and network-level blocking. Unlike traditional firewalls that only block by country, WireWall lets you block by city, region (state/province), VPN/Proxy/Tor, ASN, and more. Key Features Geographic Blocking: City-level blocking - Block specific cities worldwide (e.g., "Philadelphia", "Beijing", "Tokyo") Region blocking - Block entire states/provinces (e.g., "Pennsylvania", "California", "Tokyo Prefecture") Country blocking - Traditional country-level controls with whitelist/blacklist modes Network Protection: VPN/Proxy/Tor detection - Multi-API detection system with intelligent fallback Datacentre detection - Block AWS, Google Cloud, DigitalOcean, and other hosting providers ASN blocking - Block entire autonomous systems by ASN number Rate limiting - Per-IP rate limits with automatic temporary bans AI bot blocking - Automatically block GPTBot, ClaudeBot, and other AI scrapers Performance & Scalability: File-based cache - Scales to 1M+ IPs with zero database overhead Lightning-fast lookups - 0.5-2ms with MaxMind databases HTTP fallback - Works without MaxMind databases (though less performant) Smart caching - GeoIP cached for 30 days, VPN checks for 7 days Developer-Friendly: Priority-based system - 14 security layers evaluated in order JavaScript challenge - Detect and block headless browsers Comprehensive logging - Debug mode with detailed request information Cache management UI - Built-in interface to view stats and clear cache Triple admin protection - Logged-in users, IP whitelist, admin area bypass Real-World Results On my e-commerce site (LQRS.com), WireWall has been running for several months with impressive results: 99.98% blocking rate - Nearly all malicious traffic blocked Zero false positives - Legitimate customers unaffected Significant reduction in AWS/cloud-based automated attacks Complete elimination of VPN/proxy fraud attempts Installation cd /site/modules/ git clone https://github.com/mxmsmnv/WireWall.git Then in ProcessWire admin: Modules → Refresh Install WireWall Configure your blocking rules You're protected! How It Works - Priority System WireWall processes every request through 14 prioritised security layers: Admin Area → ALLOW (ProcessWire admin always accessible) IP Whitelist → ALLOW (manual whitelist bypass) Rate Limiting → BLOCK (excessive requests) IP Blacklist → BLOCK (permanent blocks) JavaScript Challenge → CHALLENGE (suspicious requests) VPN/Proxy/Tor → BLOCK (anonymous services) Datacentre Detection → BLOCK (cloud hosting) ASN Blocking → BLOCK (autonomous systems) Global Rules → BLOCK (known patterns) Country Blocking → BLOCK (country rules) City Blocking → BLOCK (city rules) Region Blocking → BLOCK (region rules) Country-specific Rules → BLOCK (custom rules) Default → ALLOW ✓ First match wins - once a rule triggers, evaluation stops. MaxMind Integration WireWall works best with MaxMind GeoLite2 databases (free): GeoLite2-Country.mmdb - Country detection GeoLite2-City.mmdb - City and region detection GeoLite2-ASN.mmdb - Network/ISP detection Without MaxMind, it falls back to ip-api.com HTTP API (slower, with rate limits). City and region blocking require the MaxMind City database. Download MaxMind databases from: https://dev.maxmind.com/geoip/geolite2-free-geolocation-data Technical Details ProcessWire Version: 3.0+ PHP Version: 7.4+ (8.0+ recommended) Hook Point: ProcessWire::init (runs before any page execution) Cache Location: /site/assets/cache/WireWall/ Logging: /site/assets/logs/wirewall.txt (when debug mode enabled) Why Another Firewall Module? I needed something specifically for ProcessWire that: Scales efficiently - File-based cache handles millions of IPs without database bloat Provides granular control - City and region blocking isn't available in other solutions Works offline - MaxMind databases work without external API calls Integrates natively - Built specifically for ProcessWire's architecture Stays free - Open source, no premium tiers or upsells Other solutions like Wordfence (WordPress), Sucuri (paid service), and ModSecurity (server-level) either don't integrate well with ProcessWire or lack the geographic granularity needed for fraud prevention. Resources GitHub Repository: https://github.com/mxmsmnv/WireWall Documentation: Full README with installation, configuration, and troubleshooting Landing Page: https://wirewall.org Licence: MIT (free for commercial use) Quick Start TL;DR # Install cd site/modules && git clone https://github.com/mxmsmnv/WireWall.git # Activate in ProcessWire admin Modules → Install → WireWall # Configure - Enable module - Set blocking rules (cities/regions/countries) - Enable VPN detection - Configure rate limiting - Save # Monitor Setup → Logs → wirewall.txt I'm happy to answer any questions! Has anyone else been working on security solutions for ProcessWire? I'd love to hear about your approaches and challenges. Best regards, Maxim20 points
-
This week the dev branch core version has been bumped to 3.0.254. Relative to 3.0.253 this version contains 14 commits with around 10 bug fixes and 5 feature additions. The biggest addition is Markup File Regions, which I’ve used literally every day since adding the feature two weeks ago. Fingers crossed, but I haven’t had to fix anything or make any adjustments to it so far, so it’s been very stable and reliable. I’m currently working on a client project (collaborating with Pete, Diogo and Jan P.) and that’s kept me busy the last 2-3 weeks, and likely will for a couple more. So there aren’t likely to be a lot of commits to the core during that time, but I’ll be very ProcessWire focused for sure. Working on projects using ProcessWire (as opposed to just working on ProcessWire) has always been key. But I’ve also been wanting to get the next main/master version out as soon as possible (as I’ve mentioned a couple times recently), so will be trying to do both. Thanks for reading and have a great weekend!19 points
-
Iconify Icon A bundle of fieldtype, inputfield, and admin helper modules for searching and displaying Iconify icons. Over 200,000 open source vector icons are available for selection. Requires the FileValidatorSvgSanitizer module. Be sure to abide by the license terms of any icons you use. The license of each icon set is viewable on the Iconify website. Fieldtype and inputfield modules When the FieldtypeIconifyIcon and InputfieldIconifyIcon modules are installed you can create a field of type IconifyIcon. Field config options Iconify icon set prefixes: In most cases you will want to define one or more icon set prefixes for the field, to limit the search to those particular icon sets. This is because the number of icons available through Iconify vastly exceeds the maximum of 999 results that can be returned via the Iconify search API. You can find the prefix of an icon set from its URL by browsing at https://icon-sets.iconify.design/. For example, the prefix of the icon set browsable at https://icon-sets.iconify.design/mdi/ is "mdi". Enter the icon set prefixes into the config field separated by commas. Icon preview size: Enter a width/height in pixels for the preview of the selected icon if you want to override the default. Using the inputfield Type an icon name (or part of an icon name) into the search input and a list of matching icons will be displayed. You can hover on an icon in the results to see the set prefix and name of the icon. Click on an icon to select it. If you have not defined any icon set prefixes in the field config then you can limit the search to particular icon sets by entering icon set prefixes into the search input before a colon. For example, entering "mingcute,tabler:flower" would search for icons with "flower" in their name from the "mingcute" and "tabler" icon sets. When the page is saved the selected icon is downloaded from Iconify, sanitized via the FileValidatorSvgSanitizer module, and stored within the /site/assets/iconify/ directory. Icons are not automatically deleted from this directory if they are no longer used in a page value, but if you want to clean up this directory at any point you can delete it and icons will be automatically re-downloaded when they are next needed. The field value The formatted value of a IconifyIcon field is a WireData object with the following properties: set: The icon set prefix name: The icon name path: The path to the icon file url: The URL to the icon file svg: The SVG code of the icon raw: The raw icon value that is stored in the database For example, if your icon field was named "icon" and you were outputting the src attribute of an <img> tag, you would use $page->icon->url. Or if you were outputting inline SVG code you would use $page->icon->svg. The unformatted value of a IconifyIcon field is the raw database value. Normally you won't need to deal with the raw value when using the inputfield, but if you want to use the API to set a field value then the format of the raw value is iconify--[icon set prefix]--[icon name]. Example: iconify--mingcute--flower-line. Example of object properties: Using Iconify icons in the ProcessWire admin Installing the AdminIconifyIcon module allows you to use Iconify icons as field, template or page icons in the ProcessWire admin. Icons used in the ProcessWire admin are monochrome so any colours or shades in selected icons will not be preserved. Module config You can define icon set prefixes and the icon preview size in the module config. These settings are applied to the inputfields used to set Iconify icons for fields and templates. Field and template icons An "Iconify icon" field is added to the Edit Field and Edit Template screens. When this field is populated it overrides any selection in the core "Icon" field and this field is hidden. Page icons To use an Iconify icon as a page icon for admin pages in the ProcessWire menus, create a IconifyIcon field named "page_icon" and add it to the "admin" system template. For any page using the admin template (e.g. a page representing a Lister Pro instance), open it in Page Edit and select an icon in the "page_icon" field. An example of a "Countries" Lister Pro instance with an Iconify icon: https://github.com/Toutouwai/FieldtypeIconifyIcon https://processwire.com/modules/fieldtype-iconify-icon/17 points
-
I’ve been working on a module to store ProcessWire files directly on Backblaze B2, and wanted to share it with the community. Why I Built This I needed to host video content without breaking the bank on storage costs. AWS S3 was too expensive, and I wanted something that integrates seamlessly with ProcessWire’s existing file fields. Key Features 🚀 Direct B2 Upload - Files go straight to Backblaze, no local storage needed 💰 Dirt Cheap - $6/TB/month (AWS S3 costs 5x more) 🌐 Custom Domain Support - Use your own CDN domain ⚡ Cloudflare Integration - Combine with Cloudflare for FREE bandwidth 📦 Works with Repeaters - Multiple files per repeater item 🎬 Perfect for Video - Tested with Plyr, Video.js, and HTML5 video Real Cost Savings Here’s what I’m actually paying for 500GB of video storage: Backblaze B2 + Cloudflare: - Storage: $3/month - Bandwidth: $0 (free via Cloudflare Bandwidth Alliance) - Total: $3/month AWS S3 (same usage): - Storage: $11.50/month - Bandwidth: $450/month (5TB) - Total: $461.50/month That’s a 99% savings on bandwidth costs! How It Works The module extends ProcessWire’s file fields to upload directly to Backblaze B2. You can use it just like regular file fields: // Single video <video controls> <source src="<?= $page->b2_video->url ?>" type="video/mp4"> </video> // Multiple videos in repeater <?php foreach($page->videos as $item): ?> <?php foreach($item->b2_video as $video): ?> <video controls> <source src="<?= $video->b2url ?>" type="video/mp4"> </video> <?php endforeach; ?> <?php endforeach; ?> Cloudflare CDN Integration Want free bandwidth? Here’s the magic setup: CNAME: cdn.yourdomain.com → f005.backblazeb2.com (with Cloudflare proxy) Transform Rule: Rewrite paths to include /file/bucket-name/ Module setting: Enable custom domain Now all files serve through Cloudflare’s global CDN with zero bandwidth costs thanks to the Bandwidth Alliance partnership. Setup is Simple Create Backblaze B2 bucket Configure module with API keys Create field (type: FieldtypeFileB2) Add field to template Upload files - they go straight to B2! Optional: Add Cloudflare for free bandwidth and caching. Use Cases Video hosting (my use case) Large image galleries Audio files / podcasts Downloadable resources Any high-bandwidth file hosting Technical Details Works with public and private buckets Supports custom Cache-Control headers Files are deleted from local server after upload Can use custom domains via Cloudflare CORS configurable for cross-domain access Try It Out GitHub: https://github.com/mxmsmnv/FieldtypeFileB213 points
-
This week I've added support for File Regions, part of the Markup Regions output system in ProcessWire. File Regions enable you to populate CSS and JS files with Markup Regions. I'm short on time today, so rather than writing much about it here, I've put up a documentation page for it in the API reference, which I'll link below. I'm using File Regions on a project right now and am finding it to very useful. Especially on a project where there are multiple developers, it simplifies a lot to be able to build features as self contained components, while still using the traditional route for site-wide stuff. It's something different, and I'm curious to know what you think. Here's the new documentation page for File Regions below. The page was a bit rushed, so I'll likely be amending it, but hopefully it gets across the main ideas. Thanks for reading and have a great weekend! https://processwire.com/api/ref/wire-markup-file-regions/12 points
-
@ryan I'd be interested to hear how you work on a project with multiple developers and manage keeping each developer's development instance in-sync. For example, are you using a migrations module like RockMigrations or writing migrations in a module specific to the site that adds/updates fields/templates/pages/settings when the module is updated using a version compare? Or are you doing something completely different? I'd be interested to hear how you handle this given that ProcessWire stores much of its configuration in the database.11 points
-
This module is nothing special. It adds a small JavaScript and CSS file to your page to create a nice snowfall. To adapt the snowfall to your needs you have some configuration options like snowfall density, min and max size of the snowflakes, duration time of the snowflakes and more. You have the option to start and stop the snowfall manually or depending on the date. At the moment you will find a live example here: https://www.schulfreund.at/ This example is only active in the winter season - not the whole year 😉 You can find the full docs and description and the download possibility of the module here. Have fun and enjoy the winter!!11 points
-
Hi everyone, I wanted to share a small utility module I’ve put together to help keep the /site/modules/ directory tidy. What it does: When updating modules ProcessWire renames old module directories by prepending a dot (e.g., .ModuleName). Over time, these "hidden" backup folders can clutter your file system. ProcessModuleCleaner identifies these orphaned directories and allows you to delete them directly from the admin interface. Key Features: Automatic Detection: Scans your site modules folder for any directory starting with a dot. Native UI: Built specifically for the ProcessWire backend using UIkit 3 classes for a seamless look. Interactive Selection: Uses AlpineJS for a fast and responsive "select all" and delete workflow. Safe Deletion: Uses ProcessWire's WireFileTools for reliable recursive directory removal. How to use: Install the module. Navigate to Setup > Module Cleaner. Review the list of found folders. Select the ones you want to remove and click "Delete". Screenshot / UI: The module displays a clean table with the folder name and the last modified date, so you know exactly how old those backups are. GitHub: https://github.com/markusthomas/ProcessModuleCleaner I hope some of you find this helpful for keeping your production or development environments clean! Feedback is always welcome. Cheers!10 points
-
Hey everyone! After the StripePaymentLinks module has been running smoothly, a few customers with multiple Stripe accounts asked for better analytics capabilities. The Stripe dashboard is okay, but when you have multiple accounts and need specific analysis, it quickly becomes tedious. StripePlAdmin is an admin interface that displays the data stored by StripePaymentLinks in three perspectives: Purchases: All transactions with customer details, subscription status, renewals Products: Aggregated product performance (revenue, purchases, quantities) Customers: Customer lifetime value, purchase behavior Features: Configurable columns per tab Dynamic filters (Boolean search, date ranges, number ranges) Clickable product/customer names open detail modals CSV export with active filters Summary totals at table footer You can show/hide columns and filters in the module settings as needed. Everything is very flexible. Available on GitHub and in the Modules directory. Feedback welcome! 🚀 Cheers, Mike9 points
-
I've settled on Omarchy! I spent a couple days getting used to Hyprland and tweaking it to my needs. It's a bit of a mind shift not having a taskbar/dock anymore, but I made it nice and easy to switch workspaces very quickly and do some basic window manipulations. It's nice having a Windows VM set up as well (I need Photoshop for work since I work with printing companies; CMYK support is a must). It's time to say goodbye to Windows!5 points
-
Live demo running here: https://media.smnv.org/ Attached below is the full, ready-to-go 2025 site profile site-media.zip. It’s the complete real-world implementation of FieldtypeFileB2: videos served straight from Backblaze B2, zero bandwidth cost via Cloudflare, everything polished and production-ready. Grab it, use it, butcher it — whatever you need.5 points
-
Which CMF does this? It is very challenging to have a default solution for this in the codebase IMHO. This matter becomes more complex depending on the age and size of the website. It may have several repercussions: SEO implications and content considerations, such as: - What if some pages only exist in English? Some sites may have pages with content available only in a secondary language. - What about hardcoded URLs in content (WYSIWYG fields)? - Some business logic checking the language on the templates - Etc.5 points
-
ddev import-db < ~/dumps/site.sql Have RockMigrations installed and turn on files on demand in RockMigrations: https://github.com/baumrock/RockMigrations?tab=readme-ov-file#files-on-demand after this, images on image fields will download when visiting the pages. I also have a a couple ddev hooks that trigger "site/templates/cli" scripts that do things like turning off ProCache, maybe clearing $cache if required for some particular module, turn off Mailgun, etc.4 points
-
Hooking after that method wasn't as bad as I was thinking, so this is my current quick solution: wire()->addHookAfter('ProcessLogin::buildLoginForm', function(HookEvent $event) { $form = $event->return; $form->get('login_name')->attr('autocomplete', 'off'); $form->get('login_pass')->attr('autocomplete', 'off'); $event->return = $form; });4 points
-
Hi psy, If you are looking for a quick-but-reliable way to get CSV docs into PW pages, here's a snippet I've been using for years. It might not do as much as the official module, but it will get you up and going. <?php // Script to create pages from rows in a CSV file //Open CSV file. $fileHandle = fopen("replace-with-file-name.csv", "r"); //Iterate through CSV rows. // NOTE: if you have a header row, it will be used to create a page. while (($row = fgetcsv($fileHandle, 0, ",")) !== FALSE) { // Create a new ProcessWire page from each CSV row, using the row's array 0-based index matched with the correct fields. // Set up pages in the ProcessWire page tree. $np = new Page(); // create new page object $np->template = $templates->get(xx); // Set the template to use for created pages. $np->parent = $pages->get(xxxx); // Set the parent ID for created pages. // Turn output formatting off $np->of(false); // Set field values from the 0-based index of the CSV row. $np->title = $row[0]; $np->name = $row[0]; $np->field_name1 = $row[1]; $np->field_name2 = $row[2]; $np->field_name3 = $row[3]; // Save the page $np->save(); }3 points
-
3 points
-
If you just want to sync the fields and templates you can also try the native fields/templates export/import. For most fields this works quite well. Thats how I usually do it. Sometimes I also do it the other way around and import all the pages that have changed from production to local with the native page export/import and than export the whole database (using ProcessDatabaseBackups module) from local and import that on the production site. RockMigrations is also great and I have used it for more complex stuff. One thing I did not find in RockMigrations is the option to migrate pages. Can that also be done?3 points
-
Thanks for the suggestion @BitPoet. But these config settings are for fields using the Fieldtype (and stored in the "fields" table) rather than part of the module config (stored in the "modules" table). I did get to the bottom of why the problem exists and how to work around it: You would think that when setting a default value you could check if the config setting is null (or not part of the data array for the Field) - if it's null then it means it's never been set, and if it's an empty string then it means the user has deliberately cleared the value. But saving a field goes via WireSaveableItems::save() -> WireSaveableItems::encodeData() -> wireEncodeJSON(), and the last is used without $allowEmpty set to true. So any empty value is removed from the saved data and therefore the setting will be null rather than an empty string. I saw a solution in FieldtypeText::saveFieldReady(). In your Fieldtype module you do this to check if a Field is newly created and if so set any default config values: /** * Hook called when field is about to be saved * * @param Field $field * @since 3.0.212 */ public function ___saveFieldReady(Field $field) { parent::___saveFieldReady($field); // If the field is new (it has no ID) and is being saved in ProcessField... if(!$field->id && $this->wire()->page->process == 'ProcessField') { // Set some default field config values $field->set('myFieldtypeConfigSetting', 'foo'); // ... } } This method is only available in PW >= 3.0.212 so I guess prior to that you only had the unappealing option of creating an additional autoload module bundled with your Fieldtype module and hooking Fields::save().3 points
-
Off the top of my head: In your module's install method, hook after modules::install() in that hook method, get the module config with modules::getConfig(), set your default value and do a modules::saveConfig()3 points
-
Hi @Sergio, i fully agree, this is tough to achieve. Because of the exceptions. As far as i am told joomla for example supposed to handle this a bit more easy. However they do it, i do not want to use Joomla anyway. Finally i wrote a little script which helps me to swap content. And - important for me - it includes most of the available multilingual field types. For my current project (which triggered the posting) this means i got this default language swapping thing ready in less than 5 hours. Instead of several days. Maybe this is also helpful for others... https://gist.github.com/olafgleba/1e1c33d8ad3fc22961dfba33a6ee2f363 points
-
I don't want to be too blunt and I can't speak for anyone else, but I've never referred a client to a software or service website as part of the education process. It doesn't do anything for them. You are the expert. The person making the pitch should be able to fully explain the technology stack to the extent that the conversation requires it in language they can understand because we are the interpreters. Clients trust me because I am the expert and the top 3 things they care about are these, in this order: How much is this going to cost me? Why don't we use xxx? (or, our current site is xxx I'm not sure we want to switch) When is it going to be done? Sending a client to any site for tools or software is like saying "here, do your own research". The ProcessWire site, like any other development tools/software sites, isn't there to woo clients. Most clients don't care enough to take time and truly understand it because that's not their job. If a curious client is in a position to go to websites like ProcessWire, several steps have been skipped in the client discovery/planning process IMHO. I'd even go so far as to say that if a site has "Docs" or "Documentation" in the primary nav, it's not for clients and they shouldn't be there. I hope this isn't a too hot a take... I would say that improvements could be made iteratively with more use of color for contrast, emphasis, and indicating priority. I think it's a flexible design that can evolve in whatever capacity that may be needed. This has the ability to highlight some impressive facts and figures. No notes on the content, some elements could be integrated into the current design. Even then, facts and figures are for devs. I used the word "scalability" with a manager once and they stopped the conversation to ask "wait, what does that mean?" and still didn't care when I explained. A a CMS or framework site is never going to lead to clients translating what's on the page to time or money. In all likelihood, the conversation you are having with a client at 10:00 just followed a call with their product distributor at 8:00am, their accountant at 9:00, and at 11:00 they're meeting with other members in management. Personally, I would no sooner send someone to processwire.com than I would laravel.com. You are the time and money. I agree with this. I will go out on a limb and say the number of end customers who went to the Drupal site and left thinking they need a Drupal site isn't zero, but it's probably close. If someone is hiring a Drupal developer then they're in a role where it's part of their job to understand the tech stack even if they aren't a dev. Visiting wordpress.com, it doesn't target the end user but name recognition still draws business which overcomes the website entirely. This is fair. It doesn't take a monitor that computer professionals use to get this experience. All you need is a consumer iMac. I think iteration can address concerns. I don't want to belabor the point, but to be fair, did you ever send a client to the QuarkXpress website... Just a little joke ☺️ Cheers from a fellow old school developer who built their first website in 1997 and tinkered with QuarkXpress 🍻3 points
-
AgeWire is a powerful, fully customizable age verification module for ProcessWire, built with modern web standards and powered by Tailwind CSS. Perfect for sites requiring age gates (alcohol, tobacco, adult content, etc.). Key Features Two Verification Modes: Simple Yes/No buttons Date Picker with separate MM/DD/YYYY inputs (bot-resistant) 13 Stunning Themes: Modern, Dark, Classic, Minimal, Gradient, Neon, Elegant, Corporate, Vibrant, Nature, Sunset, Ocean, Purple 4 Smooth Animations: Fade In, Slide Up, Zoom In, Bounce In International Date Formats: MM/DD/YYYY (US) DD/MM/YYYY (EU) YYYY/MM/DD (ISO) Advanced Security: Secure, HttpOnly, SameSite cookies Configurable lifetime (1 day to 6 months) Bot protection via manual date entry Smart Exclusions: Skip verification on specific templates or pages Admin pages auto-excluded Privacy & Compliance: Optional Terms & Privacy Policy checkbox Custom links to your legal pages Fully Responsive – Mobile-first design Custom CSS support Tailwind CDN integration (no build required) Installation Download from GitHub Place AgeWire folder in /site/modules/ Go to Modules > Refresh Install AgeWire GitHub: https://github.com/mxmsmnv/AgeWire Download: https://github.com/mxmsmnv/AgeWire/archive/refs/tags/v1.0.9.zip Perfect for: Wineries & breweries Vape & tobacco shops Adult content sites Age-restricted events Feedback, bug reports, and pull requests are welcome! If you like AgeWire, please ⭐ star it on GitHub! Made with ❤️ for the ProcessWire community.3 points
-
Hey, today a got this: https://github.com/FortAwesome/Font-Awesome/issues/9028 They closed all open brand icon requests and provide a link to new github discussions for new requests re-requests. So, should we do this, also when the first request is over 9 years old without any action(s) from their side? ???2 points
-
Hi Andreas, @AndZyk please can you open a new discussion (and maybe drop the URL here)? 🙏 💙 🙏 Regards, Horst 🙋♂️2 points
-
You can check out this module: https://processwire.com/modules/breadcrumb-dropdowns/2 points
-
Thank you for remembering me. The original GitHub request was by me. I think there are still many people using Font Awesome (12K stars on the repo), but if they did not include ProcessWire after 9 years, I would not get my hopes up. 😅 But we could still try. Do you want to open a discussion or should I? Regards, Andreas2 points
-
The following question might sound a bit rough at the edges, BUT are people still using FontAwesome? Sure we have it in the ProcessWire backend but I can't remember using it somewhere else in a real project. I'd say YES to re-submit to push ProcessWire but that's by far the only reason I could think of.2 points
-
<?php namespace ProcessWire; if($config->ajax) { bd('AJAX request detected'); echo "Replaced page content"; exit(); } ?> <script> function loadlist(segment='') { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("main").innerHTML = this.responseText; } }; xhttp.open("GET", "<?=$page->url?>"+segment, true); xhttp.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhttp.send(); } </script> <div id="content"> <div id="main">Basic page content</div> <p><button onclick="loadlist('')">Load List</button></p> </div> Note the replacement of the text in "main" and that Tracy detects the AJAX request.2 points
-
I second @elabx for using RockMigrations. It contains a lot of powerful utilities that you can use as you see fit. Many can be used separately, they all work well together. Tools like field and template migrations mean that you can often get away without having to perform large DB sync operations. Cheers to @bernhard for a module I use on every project 🍻2 points
-
Yes, I tried to solve this problem yesterday,but there are two options you can use: https://images.weserv.nl/ or https://github.com/thumbor/thumbor Cloudflare Transformations didn't work for sundomains. You may use ProCache module by Ryan for caching images with CDN.2 points
-
There is a module in development: https://processwire.com/talk/topic/31052-xforum-proof-of-concept-front-end-forum/ I tested it a while ago, and it worked fine. You only have to customize the styling to your needs.2 points
-
No unfortunately not. I wrote a new module WireMailBrevo that uses the API to connect instead. https://processwire.com/modules/wire-mail-brevo/2 points
-
If you dynamically add parameters to your link, you can use them in a hook: $wire->addHookBefore('Pages2Pdf::download', function($event) { /** @var Pages2Pdf $module */ $module = $event->object; $input = $event->wire('input'); $sanitizer = $event->wire('sanitizer'); // 1. Check if we are in your specific scenario // (Optional: limit this to specific templates if needed) $page = $event->arguments(0); if($page->template != 'your-list-template') return; // 2. Retrieve your filter parameters from the URL // Example URL: ?pages2pdf=1&filter_category=music&date=2023 $category = $input->get('filter_category'); $date = $input->get('date'); // 3. Build a safe filename string // It is crucial to sanitize these inputs to avoid invalid filesystem characters $filenameParts = [$page->name]; if($category) { $filenameParts[] = $sanitizer->pageName($category); } if($date) { $filenameParts[] = $sanitizer->pageName($date); } // Add unique ID or timestamp if you want to avoid caching conflicts completely // $filenameParts[] = time(); $newFilename = implode('-', $filenameParts) . '.pdf'; // 4. Overwrite the module setting for this specific request $module->set('filename', $newFilename); }); Important: The hook must be implemented via init.php. It does not work in ready.php. Actually tested it here to add the amount of portions into the filename: https://www.dothiscookingthing.de/rezepte/lachs-spiesse-mit-garnelen-aus-dem-ofen/2 points
-
2 points
-
Hi @monollonom, thank you for posting the thread. Editing the language section is the more easy part when changing the default language. If you have plenty of multilingual content, then it gets hard eventually. Therefore, having such a good starting point thanks to @gebeer , e.g. his php script to swap content of language tabs,- this whatever makes it worth the effort. I mostly work on multilingual sites/projects, so this affects me regularly,- its a pity PW doesn't handle this more smoothly. Like other CMF do.2 points
-
Finally getting onboard with .env now I have a project where the same installation is getting rolled out multiple times and I don't want any accidents (I've excluded config.php on Github but still it could happen if I get careless and we pull in a lot of other API keys) - this was the missing piece of the puzzle for me so thanks @FireWire! 🎉2 points
-
This week I’ve been working on some useful additions to our Markup Regions system, but I don’t have those additions quite ready to commit to the core just yet. Hopefully next week they will be ready. What it involves is the ability to populate regions within CSS, JS, SCSS, LESS files. So I might output a <style> tag in my markup (for example), but the styles go into a CSS file rather than in the HTML output. That CSS file combines and contains all such instances, and can then be loaded from a dedicated <link> tag in the document head. You could do the same with JS, but using <script> tags instead. I’m not sure I’ve explained it well just yet, so I’ll have a better description of it next week, along with some practical examples. It’s very simple and I think examples will make it obvious. Stay tuned, have a great weekend and thanks for reading!2 points
-
Good day, whoever needs this years later) This trick for hook is obsolete after the newly introduces Page::renderPage hook (see here). That is great, but it does break the old way of getting page with the line quoted above. Change the code to something like this: wire()->addHookBefore('Page::renderPage', function (HookEvent $event) { $page = $event->object; ...2 points
-
Hello @ all The new version 2.3.0 comes with a brand new feature: the possibility to turn a form into a multi-step form. Many thanks to @Jan S. for the idea and the support in testing during the development of the new feature. In a nutshell: A multi-step form is a long form divided into multiple steps. At the end of each step, the user clicks on a "Next" button to go to the next section. In the final step a summary of the data entered will be displayed to the user. The user now has the option to change some of the data if necessary before finally submitting the form. Typical use cases are very long forms, surveys or quizzes. I have written an extra chapter in the docs with a lot more information, which you can find here. There are only 2 restrictions for multi-step forms to work properly: The send button must be after the last step (by the way, it wouldn't make sense to put it anywhere in between ;-)) File upload fields must be placed in the last step (otherwise they won't work) To turn a form into a multi-step form, you only need one new method: addStep() You need to add this method to the form object in the places where you want to make the cut: $form = new \FrontendForms\Form('simpleform'); $firstname = new \FrontendForms\InputText('firstname'); $firstname->setLabel('Firstname'); $firstname->setRule('required'); $form->add($firstname); $lastname = new \FrontendForms\InputText('lastname'); $lastname->setLabel('Lastname'); $lastname->setRule('required'); $form->add($lastname); $form->addStep(); // first step $email = new \FrontendForms\InputEmail('email'); $email->setLabel('Input Email'); $email->setRule('required'); $form->add($email); $form->addStep(); // second step $birthday = new \FrontendForms\InputDate('date'); $birthday ->setLabel('Birthday'); $form->add($birthday ); $form->addStep(); // third step $message = new \FrontendForms\Textarea('message'); $message->setLabel('My message'); $form->add($message); $form->addStep(); // fourth step $button = new \FrontendForms\Button('submit'); $button->setAttribute('value', 'Send'); $form->add($button); if($form->isValid()){ print_r($form->getValues()); // do what you want } // render the form echo $form->render(); That is all! You can find more examples here. To be informed of all the changes in this release, please read the changelog. As always, please keep an eye on whether everything is working as expected and report any issues you discover here or directly on GitHub. Jürgen2 points
-
Hello again! The new AppApi release v1.4.0 is live now! Changes in 1.4.0 (2025-11-01) Add compatibility for ProcessWire instances installed in a subdirectory (Thank you @saerus for mentioning this issue) Add helper functions that can manipulate subdirectory links. -> Can be very handy for using ProcessWire as a headless CMS for your JavaScript applications (See FAQ for more information) Add config param to disable automatic adding access control headers (Thank you @gerritvanaaken for the ticket) Fix an issue where adding trailing slashes automatically lead to problems with route parameters (Thank you @gingebaker for the ticket) Thank you all for using AppApi, leaving feedback and for posting Github Issues and PRs. Thanks to you, the module keeps getting better and better.2 points
-
Hi @olafgleba If you are talking about the language when a visitor first visit the site. Take a look at the following. I have just changed the default language of my site. https://processwire.recipes/recipes/change-homepages-default-language/ Gideon1 point
-
Hello! I use .env files on every ProcessWire project to manage environment-specific configurations and settings. I've built a ProcessWire specific utility that makes using .env files a breeze. This post isn't intended to debate .env vs. config.php, use what you're comfortable with and prefer. That said, here are a few benefits to using .env files that may make it worth considering: Native support on web servers, including Apache, they are not served via http request by default True environment based secrets and settings management A standard file widely used and accepted as the method for managing secrets and sensitive values Able to store any value whether sensitive or not and access them globally Building a dedicated solution came from a discussion here on the forums where I threw together a rough implementation that needed little polish for real world use. It makes use of phpdotenv. This utility delivers the following: Easy use of and access to .env variables Caching the parsed .env for performance. This is a significant part of this utility and addresses a known need Automatic .env change recognition and re-caching Utilities to make working with environment variables feel ProcessWire native and a few extra nifty things What it isn't: A module. It's not possible to make a module for this need because the information kept in a .env file needs to be available before ProcessWire boots. Adding this to a new or existing project is very easy. It's designed to implement quickly and use immediately in your projects. Full documentation is provided in the Github repository. Here are a few examples of using this tool: <?php namespace ProcessWire; use Env\Env; if(!defined("PROCESSWIRE")) die(); $env = Env::load(__DIR__ . '/../'); // Make env available throughout the application $config->env = $env; $config->dbName = $env->get('DB_NAME'); $config->dbUser = $env->get('DB_USER'); $config->dbPass = $env->get('DB_PASS'); // Env::get() takes a second argument that is the fallback value if for any reason DEBUG doesn't exist $config->debug = $env->get('DEBUG', false); // Conditional values. By default, if the condition is falsey, Env::if() returns null $config->adminEmail = $env->if('APP_ENV', 'production', 'you@youremail.com'); // A fourth argument will be returned if condition is false, truthy/falsey output can be env var names or specific values $config->adminEmail = $env->if('APP_ENV', 'production', 'ADMIN_EMAIL', 'you@youremail.com'); // Conversely, you can also check if a condition is not met. $config->adminEmail = $env->ifNot('APP_ENV', 'development', 'ADMIN_EMAIL'); // Use one env value to set multiple config properties $config->advanced = $env->if('APP_ENV', 'production', false, 'ENABLE_ADVANCED'); // Never in production, change locally in env as needed $config->adminEmail = $env->ifNot('APP_ENV', 'development', 'ADMIN_EMAIL'); // Never send an email in dev, always on staging/production These helper methods make is very straightforward to implement a dynamic config file. This can be useful for using secure .env values while retaining the ability to commit and upload some types of changes to your config.php file without needing to touch .env values on the server. You can also use Env::pushToConfig(). As long as you use the "screaming snake case" naming convention for your environment variable names, type and value recognition are handled automatically. <?php $env->pushToConfig($config, [ 'usePageClasses' => true, 'templateCompile' => 'TEMPLATE_COMPILE', 'debug' => ['DEBUG', false], // Fallback to false 'advanced' => $env->if('APP_ENV', 'production', false, 'ENABLE_ADVANCED'), 'adminEmail' => $env->ifNot('APP_ENV', 'development', 'ADMIN_EMAIL'), 'httpHosts' => [ 'something.com', 'staging.something.com', 'something.ddev.site' ], ]); Using Env in your application files and templates can be very useful. In the above example we assigned the Env object to $config->env. This lets you access your .env variables globally and use some helpful methods. <?php if ($config->env->eq('APP_ENV', 'development')): ?> <script src="/some/development/stuff.js"></script> <?php endif ?> <?php if (!$config->env->exists('GOOGLE_API_KEY')) { $wire->error('A Google API key could not be loaded from the environment file.'); } try { // Do something that could fail } catch (Exception $e) { $message = $config->env->if('APP_ENV', 'production', 'Oh no. Friendly message here', $e->getMessage()); } This utility also automatically casts 'true' and 'false' values in .env files to booleans, and casts numbers to integers. It also includes several configuration options. I have been using this tool in production and have been happy with it. Maybe you might find it helpful in your projects as well. If you like it, throw a star on the repo. If you run into any bugs, file an issue on Github. I may publish it as a composer package at some point. Env utility for ProcessWIre on Github.1 point
-
Good catch. Definitely an oversight in the template code itself. The old version does not wrap all elements in an anchor tag. Comparable example.1 point
-
After updating to 2.1.0 I got this error but only if I try to go to the settings: Fatal Error: Uncaught Error: Class "RecursiveIteratorIterator" not found in site/modules/PageProtector/PageProtector.module.php:743 The rest works fine.1 point
-
1 point
-
I get this error… Warning: Undefined array key "message_override__1021" in /var/www/html/site/assets/cache/FileCompiler/site/modules/PageProtector/PageProtector.module.php on line 519 Warning: Undefined array key "prohibited_message__1021" in /var/www/html/site/assets/cache/FileCompiler/site/modules/PageProtector/PageProtector.module.php on line 520 is it just me? EDIT: That's only when I do this: $options = array( "page_protected" => true, ); $page->protect($options); as described here… but when I just do: // _main.php $page->protect = true; The warnings are gone and the page is protected programmatically. Cheers!1 point
-
Here's another website that i recently made that I would like to share with the community: https://www.w2-ingenieure.de/ W² Ingenieure (which is german and translates to "W² Engineers") is a small office that offers that develops, modernizes, and optimizes living and working spaces in Germany like: Schleswig-Holstein, Hamburg, and Lower Saxony. Whether for private households, commercial enterprises, public institutions, or industrial plants – they plan and implement customized solutions for even the most complex requirements. This project is a redesign of an existing website. While the old website had plenty of good content, there were multiple flaws in the design (especially the mobile version of the website) so my main task was not to make a from-the-ground-new-concept but to give it a better, functional and more polished look based on the CI. As we are talking about an engineering company that offers planning for the construction industry the look of the site hat to be sleek, clean, somehow modern and overall "serious". We are not talking about a design-agency website here. Tech Talk: - UiKit as frontend framework - RockPageBuilder for content creation and editing - TextformatterRockDown to enable headline formatting - RockFrontend for Ajax Endpoints (used in form submissions) - RockDevTools for Asset Management and Minification - SEO Maestro for SEO meta data - PageImageSource for webp image creation - FileMover as a workaround for a global media management solution - WiremailSMTP to handle form submissions So here it is: The website consists of several page templates, including: - Homepage - Content Page - Project Page - Job Page - etc. The Homepage and Content Page templates can be populated with pre-defined content-blocks via @bernhards RockPageBuilder. This is straight-forward and easy-to use. The user can chose between multiple content elements and place those elements in any order they want: For Example we have: - Textfields - Teaser in multiple variants - Description Lists - Hero Title Image Sections - etc. Once added the content can be edited directly in the frontend or inside a convenient popup window (or from the backend page edit view of course). Other templates like the Project Page offer a more strict, predefined, layout to achieve a uniform look throughout any project page that is crated. These type of pages can be populated from the backend more easily: I have to keep my attachment file list small, so please have a look on this site for yourself and don't hesitate to ask any questions if you would like to know more about the tech in the background. Have a great week! Stefan1 point
-
I built "my" first website in `96 with Adobe PageMill, fighting with tables to craft the basic layout it had. It was for a bank, a handful of static pages. I had no prior experience with HTML... :P1 point
-
Btw, the old site can be accessed just by appending ?oldsite=1 to any URL (temporarily, anyway).1 point