Jump to content

Search the Community

Showing results for 'files'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Welcome to ProcessWire
    • News & Announcements
    • Showcase
    • Wishlist & Roadmap
  • Community Support
    • Getting Started
    • Tutorials
    • FAQs
    • General Support
    • API & Templates
    • Modules/Plugins
    • Themes and Profiles
    • Multi-Language Support
    • Security
    • Jobs
  • Off Topic
    • Pub
    • Dev Talk

Product Groups

  • Form Builder
  • ProFields
  • ProCache
  • ProMailer
  • Login Register Pro
  • ProDrafts
  • ListerPro
  • ProDevTools
  • Likes
  • Custom Development

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


AIM


MSN


Website URL


ICQ


Yahoo


Jabber


Skype


Location


Interests

  1. This week there were 45 commits on the dev branch for ProcessWire 3.0.268. The most interesting updates were: Added checkboxes in the Setup > Fields list, so you can bulk delete or export. Added new getRaw() and saveRaw() methods for WireCache ($cache) Added $page->meta() support to PagesExportImport export and import (via @jploch) Added WireTests test framework files and API.md documentation for the following, which finishes up the Inputfield modules: InputfieldTinyMCE InputfieldImage InputfieldFile InputfieldTextTags InputfieldSelector InputfieldPage InputfieldIcon InputfieldPassword InputfieldPageAutocomplete InputfieldHidden InputfieldPage InputfieldPageTitle InputfieldFieldset InputfieldMarkup InputfieldPageName InputfieldName InputfieldPassword InputfieldForm These were done using the AgentTools scheduled tasks Round-Robin feature that rotates between different agents. In this case, between DeepSeek v4 Pro, Kimi K2.7 Code, GLM 5.2 and Claude Opus 4.8. After each API.md and code review was finished, they were queued to GPT 5.5 who verified everything, made any necessary fixes, and then built a WireTests ClassName.test.php file for each. Following that Claude Sonnet 4.6 gave each API.md, ClassName.test.php and ClassName.module a final review and commit. In addition, we have a new version of AgentTools that adds the following: New MCP server support New WireTests coverage Improved CLI safety and migration checks New AgentTools logo added to README (design credit to GPT 5.5) There's also a new version of ProCache posted this week that adds CLI command support, AGENTS.md and API.md files, and fixes a few bugs too. As always, visit the ProcessWire Weekly for the latest news and updates. Thanks for reading and have a great weekend!
  2. Hi everyone, I’m happy to share the first public testing release of Mercato, a ProcessWire-native commerce toolkit. Mercato is not just a “shop template” or a simple cart module. The goal is to provide a flexible commerce layer that works the ProcessWire way: pages, templates, fields, permissions, hooks, and site-level customization. The basic idea is: Your website should not have to become “the shop system”. The shop should become part of your ProcessWire site. Mercato can be used as a full storefront, but it is also designed for custom ProcessWire websites that need commerce features without being forced into a rigid shop structure. What Mercato includes Products as ProcessWire pages Cart and checkout Orders stored as ProcessWire pages Stripe, Mollie, PayPal, bank transfer, and demo payment support Discounts and coupons Inventory handling Preorder and backorder support Digital products and downloads Fulfilment: carrier delivery, store pickup, local delivery Customer records Abandoned checkout recovery tools Refunds and payment operation tracking Webhook/event logs Reports and CSV exports Launch-readiness checklist Public order status and receipt pages Headless/read API surfaces A complete installable demo storefront Demo storefront A fresh install creates a real demo storefront called Arlberg Ceramics. It is not just placeholder content. The demo includes: physical products digital products gift cards product collections product images discounts low-stock products sold-out states preorder/backorder examples checkout policy pages order confirmation pages delivery, pickup, and local delivery scenarios The demo is meant to help developers test the full commerce flow immediately after installation. Existing sites Mercato is designed to add commerce functionality to an existing ProcessWire site without taking over the whole website. It creates Mercato-specific fields, templates, pages, permissions, products, collections, and order storage. It does not remove existing site content. Bundled storefront template files are copied into /site/templates/ only when the target files are missing. Existing template files are not replaced unless template overwrite is explicitly enabled in the module settings. That said, this is a commerce module and it changes the site schema, so please test on a staging copy first and make a backup before installing it on an existing/production site. Current status This is the first public release and should be treated as a testing release. I have tested the installer, demo storefront, checkout flow, admin screens, and basic payment workflows, but I would really appreciate feedback from real ProcessWire projects and different hosting setups. Things I’m especially interested in: installation issues gateway setup issues checkout edge cases admin UX feedback missing hooks or extension points template customization feedback real-world commerce scenarios I have not covered yet Repository GitHub: https://github.com/mxmsmnv/Mercato Requirements ProcessWire 3.0.200+ PHP 8.1+ Final note This is a big personal milestone for me. I have wanted ProcessWire to have a serious, modern commerce foundation for a long time. Mercato is my attempt to build that foundation in a way that respects how ProcessWire developers actually build websites. Feedback, testing, issues, and ideas are very welcome.
  3. I am trying to learn php and "proper" dev practices (terminal, git, staging). My background is in no-code apps, but I have a solid knowledge of HTML and CSS. I started building a personal site on Neocities, very nice, but I realised that I needed a CMS. ProcessWire has been fabulous so far, while I've been creating files on my live hosting (LOL). I'm using Ai to help guide me through the "proper dev" practices, and honestly, it's been great. But now we're stuck. I'm trying to load my site locally. I've been getting various errors, blank screens. Ai insists that I need bootstrap.php and I need to get a fresh install of PW. When I look at the files in PW, there is no bootstrap.php. This page https://processwire.com/docs/front-end/include/ mentions bootstrapping, but no mention of the "missing" bootstrap.php file. Any ideas?
  4. This week we've ProcessWire 3.0.267 on the dev branch, here are some highlights (commits): The entire WireTests module has been moved into the core. All of the tests now live alongside the classes that they test. The WireTests module is used from the command line. Once installed, you can type "php index.php test" for a list of WireTest commands. If you already have the non-core WireTests module installed, I recommend uninstalling it and installing the core version. More than a dozen new WireTests and API.md documentation files have been added this week (this is where the biggest additions of the week are). Many improvements to the CLI "docs" command, especially with regard to chapter retrieval. New faster $modules->refresh() method from @matjazp New HOWTO-API.md documentation that outlines how to write API.md files for your own modules. New getFresh() and getRaw() methods added to $fields and $templates. These do the same as their $pages method equivalents (getFresh and getRaw), except for fields and templates. This was requested by an agent in AgentTools. This week we also have a new guest blog post! Page's best kept secret: the meta() method Thanks for reading and have a great weekend!
  5. I thought about this as well... somewhere last year/the last years and even prior but couldn't fight my innerer Schweinehund* to follow and keep up with that thought. Back then... everything in that direction was still somehow complicated and not that easy. But today... this could be a super awesome workflow, yet not as easy to share between developers as TailwindCSS. Back to what I remember. What I remember is: Using a more modern CSS reset (Andy Bell) - https://piccalil.li/blog/a-more-modern-css-reset/ Using custom web components (Kevin Powell) - https://www.youtube.com/watch?v=b_x3kzapvcI Using NoBuild - and only individual files (DHH/David Heinemeier Hansson) - https://x.com/dhh/status/1719041666412347651 * The innerer Schweinehund (literally "inner pig-dog") is the iconic German idiom for that stubborn, lazy voice inside you. It's the ultimate excuse for procrastination, the force that tells you to stay in bed, skip the gym, or not build your own CSS framework when you know you should be productive.
  6. Revisiting this topic again... I want to use vanilla CSS as much as possible moving forward, but I'm trying to find a "base" from which to start. This base would come with an opinionated way of organizing files, a reset, breakpoints and perhaps stub-out certain components and use all the latest CSS features. I can't seem to find anything like that and that's also pretty recent. Any suggestions?
  7. This module allows you to automatically rename file (including image) uploads according to a configurable format This module lets you define as many rules as you need to determine how uploaded files will be named and you can have different rules for different pages, templates, fields, and file extensions, or one rule for all uploads. Renaming works for files uploaded via the admin interface and also via the API, including images added from remote URLs. Github: https://github.com/adrianbj/CustomUploadNames Modules Directory: http://modules.processwire.com/modules/process-custom-upload-names/ Renaming Rules The module config allows you to set an unlimited number of Rename Rules. You can define rules to specific fields, templates, pages, and file extensions. If a rule option is left blank, the rule with be applied to all fields/templates/pages/extensions. Leave Filename Format blank to prevent renaming for a specific field/template/page combo, overriding a more general rule. Rules are processed in order, so put more specific rules before more general ones. You can drag to change the order of rules as needed. The following variables can be used in the filename format: $page, $template, $field, and $file. For some of these (eg. $field->description), if they haven't been filled out and saved prior to uploading the image, renaming won't occur on upload, but will happen on page save (could be an issue if image has already been inserted into RTE/HTML field before page save). Some examples: $page->title mysite-{$template->name}-images $field->label $file->description {$page->name}-{$file->filesize}-kb prefix-[Y-m-d_H-i-s]-suffix (anything inside square brackets is is considered to be a PHP date format for the current date/time) randstring[n] (where n is the number of characters you want in the string) ### (custom number mask, eg. 001 if more than one image with same name on a page. This is an enhanced version of the automatic addition of numbers if required) If 'Rename on Save' is checked files will be renamed again each time a page is saved (admin or front-end via API). WARNING: this setting will break any direct links to the old filename, which is particularly relevant for images inserted into RTE/HTML fields. The Filename Format can be defined using plain text and PW $page variable, for example: mysite-{$page->path} You can preserve the uploaded filename for certain rules. This will allow you to set a general renaming rule for your entire site, but then add a rule for a specific page/template/field that does not rename the uploaded file. Just simply build the rule, but leave the Filename Format field empty. You can specify an optional character limit (to nearest whole word) for the length of the filename - useful if you are using $page->path, $path->name etc and have very long page names - eg. news articles, publication titles etc. NOTE - if you are using ProcessWire's webp features, be sure to use the useSrcExt because if you have jpg and png files on the same page and your rename rules result in the same name, you need to maintain the src extension so they are kept as separate files. $config->webpOptions = array( 'useSrcExt' => false, // Use source file extension in webp filename? (file.jpg.webp rather than file.webp) ); Acknowledgments The module config settings make use of code from Pete's EmailToPage module and the renaming function is based on this code from Ryan: http://processwire.com/talk/topic/3299-ability-to-define-convention-for-image-and-file-upload-names/?p=32623 (also see this post for his thoughts on file renaming and why it is the lazy way out - worth a read before deciding to use this module). NOTE: This should not be needed on most sites, but I work with lots of sites that host PDFs and photos/vectors that are available for download and I have always renamed the files on upload because clients will often upload files with horrible meaningless filenames like: Final ReportV6 web version for John Feb 23.PDF
  8. How KeyHelp for ProcessWire was built: from a phone idea to a tested module I have been building modules for ProcessWire for a long time, but this one had a slightly different origin story. KeyHelp started not as a carefully planned “module project”, but as a practical question while I was away from my computer: What if ProcessWire could manage a hosting panel directly from the admin area? The initial research happened on my phone. I was looking at how other systems handle hosting integrations, especially WordPress. WordPress has a huge ecosystem around this: hosting panels, one-click installers, backup plugins, deployment tools, billing integrations, and managed hosting workflows. Panels like HestiaCP, FastPanel, CyberPanel and CloudPanel all have their own approaches to WordPress automation. That made me think about ProcessWire. ProcessWire is a very strong developer CMS, and I have built modules for it for years, but hosting operations usually still live outside the CMS: domain setup, databases, SSL, PHP versions, DNS records, FTP accounts and cron jobs. For editors and site owners, that means switching between the CMS and the hosting panel. For developers, it means repeating small operational tasks that could probably live closer to the project. The research then moved toward German hosting panels. I used Google Gemini on my phone to explore that landscape. The conversation started around hosting panel integrations, WordPress automation, CloudPanel, CLI/API wrappers and then German panels specifically. KeyHelp stood out because it is widely used in the German hosting world and has a REST API. I also looked at the broader German ecosystem: LiveConfig, Froxlor, older i-MSCP setups, and custom panels from German hosts like All-Inkl and Mittwald. That context mattered, because KeyHelp is not just “another control panel”. It belongs to a hosting culture where stability, server control and GDPR-friendly infrastructure matter. After that research, I moved to Claude on my phone for the first implementation attempt. The first prompt was essentially: Need build integration module with KeyHelp web panel for administration Webserver inside PW Then I defined the first scope: Domains: create, delete, list Clients / users Databases Email accounts SSL / Let’s Encrypt PHP settings DNS records A ProcessWire admin dashboard with server status, domains and database widgets API access through a KeyHelp admin key Claude produced the first module draft. It created the initial structure with a module file, assets, views, dashboard, domain list, create forms, SSL/PHP/DNS screens, client views, database screens and basic cache/API handling. But the first version was too monolithic. So the next correction was immediate: Do not make it a monolith. Put the settings into the module. Where is the Process module? That changed the architecture. The module was split into: KeyHelp.module.php for configuration, API client, cache, debug logging and module settings ProcessKeyHelp.module.php for the ProcessWire admin UI later, multiple traits under src/ProcessKeyHelp/ views under views/ CSS/JS and Remix Icon SVG assets under assets/ That was the first important turn: not just “make something that works”, but make it feel like a real ProcessWire module. Claude also helped shape the first permission model. The early version was basically superuser-only, but it became clear that a real module needed ProcessWire permissions. The model became: keyhelp-view keyhelp-edit keyhelp-delete keyhelp-server So even before the heavy testing phase, the direction was already moving from “prototype” to “proper ProcessWire admin module”. When I got home, I saved the generated module, opened the module folder in Codex, and the real work began. At that point I also decided to buy a fresh Hetzner test server specifically for this module. That turned into its own small side quest: I had to create a Hetzner account, go through identity verification, take a photo of my government ID / driver license, take a selfie, submit everything, and wait for approval before I could even create the server. Only after that could I create the VPS, install KeyHelp, connect it to a real domain, create an API key and start testing the ProcessWire module against a real hosting panel. The server uptime later showed: 17h 12m That became a nice marker of the whole process. This was not just a fake UI built against assumptions. There was a real KeyHelp panel, a real API key, a real ProcessWire installation, and a real remote server used specifically to test the integration properly. The first real problem appeared immediately in ProcessWire: Cannot reach KeyHelp API: cURL: Could not resolve host: key.smnv.org That led to the first practical improvements in Codex: API URL handling; API access notes; SSL verification settings; DNS resolution override; better module configuration hints; safer debug logging. The KeyHelp panel showed API version 2.14, so the implementation was aligned with the KeyHelp REST API docs. From there, the module became a loop of implementation, browser testing, corrections and UI review. This was the main Codex phase. I had Chrome open with two real things side by side: the KeyHelp panel on the test server; the ProcessWire admin module running on my site. Codex was editing the module files locally, and I was checking the result in the browser. I asked it to click through pages, inspect forms, open tabs, check GET/POST behavior, test UI states, and compare the result with what I saw. The module was tested in Chrome and in the in-app browser across: dashboard domains domain view SSL tab PHP tab DNS tab clients databases email FTP SSL certificates cron jobs installer server page module settings A lot of the work was not glamorous. It was small things that make a module feel real: tabs did not work correctly at one point; buttons had unwanted underlines; Font Awesome icons were jumping because more than one icon set was involved; icons were replaced with Remix Icon SVGs; tables were too custom and started hiding API data; badges were too small; breadcrumbs were inconsistent; some titles and breadcrumbs were not translated; German labels were missing in places; uk-table-small, uk-margin-remove, kh-mono and other styling leftovers had to be removed; dashboard and server screens needed better information layout; module settings needed better UI/UX; slow API pages initially felt frozen, so lazy background loading was added. This is where the human + AI workflow was useful. Codex would implement a change. Then I would look at the browser and say things like: “the tabs are broken” “what happened to the design?” “why is there a big left gap?” “the icons jump” “this table is wrong” “the German version still says Refresh” “this should look like Ichiban” “remove custom table styles” “don’t use Font Awesome” “test this in Chrome” “go through all tabs yourself” Then Codex would inspect the code, patch it, test again, and refine the result. There was also a strong UI direction: the module should not look like a random SaaS dashboard. It should feel like a ProcessWire admin tool. Dense, calm, useful, and close to the Ichiban / AdminThemeUikit style. No decorative landing page, no marketing hero, no unnecessary cards inside cards. The installer became the biggest feature. The goal was: From ProcessWire Admin, choose a KeyHelp domain, choose ProcessWire stable or dev, and let the module install ProcessWire there. That meant the module needed to: resolve the domain document root; support the case where KeyHelp and ProcessWire run on different hosts; support local and SSH remote deployment; download the ProcessWire archive; unpack it; create a KeyHelp database and database user; generate a random admin URL; generate secure credentials; run the ProcessWire CLI installer; adapt Apache configuration for KeyHelp; remove installer files; store credentials securely. At first, the installer assumed the document root was visible locally. That was wrong for real deployments. The KeyHelp panel can be on one server and the ProcessWire admin module on another. So the installer had to learn the difference between local filesystem and remote SSH deployment. That was a very important correction. The module should not only work on my local setup. It should handle the realistic case where the ProcessWire admin site and the KeyHelp hosting server are separate machines. Then came another important question: After ProcessWire is installed, where are the generated credentials stored? The answer became: in a module-managed table, encrypted using the ProcessWire site salt. The domain list now shows a ProcessWire badge when an installation is known, and the domain detail page can show stored admin URL, admin login and database credentials to users with the right permission. There is also a GitHub module installer for already installed ProcessWire sites. It checks whether ProcessWire exists in the target path, downloads a GitHub repository archive, validates PHP syntax, and copies it into /site/modules. The server page also evolved during testing. At first it was too raw. Then it became a proper admin view with: server information; software versions; resource usage; services; server reboot action; links back to KeyHelp where the API does not expose something. A specific note was added because the KeyHelp REST API does not expose start/stop/restart endpoints for individual services. Server-level reboot is available through POST /server/reboot for KeyHelp 26.0+. Debugging support was added too. The module can log sanitized API requests, payloads, responses, cache hits and timings to keyhelp-debug, while redacting sensitive values like API keys, passwords, tokens and secrets. One of the important late-stage changes was performance. Some KeyHelp API calls could take many seconds. At one point Tracy showed pages taking a long time because data was being fetched directly before the admin page rendered. That is bad UX: it makes the admin feel frozen. So the module was changed so slow API-backed pages render an admin shell first, then load data in the background. The user sees that the page is alive, and the data fills in when ready. The module also gained English and German UI support. Since KeyHelp is a German hosting panel, German translation was not just a nice extra. It made sense for the module’s audience. The documentation evolved during the same process: README was rewritten in a release-ready style; German documentation was added; CHANGELOG was made first-release friendly with only an Added section; sponsorship metadata was added; version was set to 100; AGENTS.md was added so future AI agents understand how to work with the module, what not to touch, how the installer works, what API calls exist, and how to test safely. Near the end, the repository was cleaned up: the monolith was split into src/, views/ and assets/; tests were kept local and ignored; unused generated image assets were removed; README was kept version-free; the GitHub branch was recreated using an orphan commit so the public repository starts cleanly with one init commit. The final result is not only a KeyHelp API wrapper. It is a ProcessWire admin integration for a German hosting panel, with a real installer workflow for creating ProcessWire sites on KeyHelp domains. The full path looked roughly like this: I researched hosting integrations and German panels with Google Gemini on my phone. I used Claude on my phone to create the first KeyHelp module prototype. I corrected the architecture so it became a real ProcessWire module pair instead of a monolith. I created a Hetzner account and went through ID/selfie verification. I bought a fresh test server specifically for this module. I installed KeyHelp on the server. I saved the generated module locally. I opened the module folder in Codex. I connected the module to the real KeyHelp API. I tested the UI and API workflows in Chrome. I repeatedly corrected UX, tables, icons, tabs, translations and layouts. I added the ProcessWire installer. I added SSH remote deployment. I added encrypted credential storage. I added GitHub module installation for existing ProcessWire sites. I added lazy loading for slow API pages. I cleaned up README, German docs, CHANGELOG and release metadata. I published the repository as a clean orphan init commit. This is what I found interesting about the process: the AI did not replace testing or product judgment. Gemini helped with research and context. Claude helped create the first prototype. Codex helped turn it into a tested module by repeatedly editing code, running checks, using Chrome, and reacting to very specific feedback from the real UI. The quality came from the loop: build, open in browser, click, notice what feels wrong, fix, test again. The test server uptime, 17h 12m, is a funny detail, but it captures the mood of the whole thing: a fresh server bought just to make sure this module was not theoretical. Repository: https://github.com/mxmsmnv/KeyHelp
  9. Export your ProcessWire site structure as comprehensive, AI-optimized documentation for ChatGPT, Claude, Copilot, and other AI coding assistants. What It Does Context automatically generates complete documentation of your ProcessWire site in formats specifically optimized for working with AI: 📊 Site Structure Complete page hierarchy exported as JSON, TOON, and ASCII tree Shows all relationships, templates, URLs, and metadata Smart collapsing for large page lists 📋 Templates & Fields All template definitions with complete field configurations Field types, options, requirements, default values Special handling for Repeater, Matrix, Table fields 📦 Content Samples Real page examples exported for each template Shows actual data formats and field usage Helps AI understand your content patterns 💾 Code Snippets Customized selector patterns for your site type Helper functions and utility code API implementation examples 🤖 AI Prompts Ready-to-use project context file Template creation prompts Debugging assistance prompts Session continuity templates 🖥️ CLI Commands Export from command line for AI agents Query templates, fields, and pages directly Perfect for Claude Code, Cursor, Windsurf integration Dual Format Export (The Game Changer!) Context exports in two formats simultaneously: JSON Format Standard format for development tools, APIs, and compatibility TOON Format (AI-Optimized) ✨ Token-Oriented Object Notation designed specifically for AI prompts: 30-60% fewer tokens than JSON Significantly reduces API costs Same data, more compact representation No external dependencies - pure PHP Real Savings Example For a typical ProcessWire site with 50 templates: structure.json (15,000 tokens) → structure.toon (8,500 tokens) = 43% savings templates.json (8,000 tokens) → templates.toon (4,000 tokens) = 50% savings samples/*.json (12,000 tokens) → samples/*.toon (6,500 tokens) = 46% savings Cost Impact (Claude Sonnet pricing): JSON export: $0.105 per AI interaction TOON export: $0.057 per AI interaction Save ~$5/month if you use AI assistants 100 times/month Installation cd /site/modules/ git clone https://github.com/mxmsmnv/Context.git Then in admin: Modules → Refresh → Install Or download from ProcessWire Modules Directory Quick Start Web Interface Setup → Modules → Context → Configure Choose your site type (Blog, E-commerce, Business, Catalog, Generic) ✅ Enable "Export TOON Format" (recommended for AI work!) Enable optional features: ✅ Export Content Samples ✅ Create Code Snippets ✅ Create AI Prompts ✅ Generate SKILL.md for AI Agents Click "Export Context for AI" Files appear in /site/assets/cache/context/ CLI Interface # Full export php index.php --context-export # Export TOON format only (fastest, smallest) php index.php --context-export --toon-only # Query specific data php index.php --context-query templates php index.php --context-query fields php index.php --context-query pages "template=product, limit=10" # Quick stats php index.php --context-stats # Help php index.php --context-help Perfect for AI coding agents like Claude Code, Cursor, and Windsurf! Generated Files /site/assets/cache/context/ ├── README.md # Complete documentation ├── SKILL.md # AI agent skill definition ├── structure.json / .toon # Page hierarchy ├── structure.txt # ASCII tree ├── templates.json / .toon # All templates & fields ├── templates.csv # Templates in CSV ├── tree.json / .toon # Combined structure ├── config.json / .toon # Site configuration ├── modules.json / .toon # Installed modules ├── classes.json / .toon # Custom Page classes │ ├── samples/ # Real content examples │ ├── product-samples.json │ └── product-samples.toon # 46% smaller! │ ├── snippets/ # Code patterns │ ├── selectors.php # Customized for your site type │ ├── helpers.php # Utility functions │ └── api-examples.php # REST API examples │ └── prompts/ # AI instructions ├── project-context.md # Complete project overview ├── create-template.md # Template creation guide ├── create-api.md # API creation guide ├── debug-issue.md # Debugging helper └── project-summary.md # Session continuity template Using with AI Assistants Web Interface Upload Upload TOON files to save tokens and costs: 📎 structure.toon 📎 templates.toon 📎 prompts/project-context.md Then ask your AI assistant: "Help me create a blog post template with title, body, author, categories, and featured image. Follow the existing patterns from templates.toon" AI Coding Agents (Claude Code, Cursor, Windsurf) 1. Tell your agent to read the docs: Read /site/modules/Context/AGENTS.md 2. Agent can now export context: php index.php --context-export --toon-only 3. Agent queries specific data: php index.php --context-query templates 4. Agent reads exported files: Read SKILL.md, then structure.toon and templates.toon The AI has complete context of your site and can generate code that follows your exact patterns! Site Type Customization Code snippets automatically adapt to your site type: Blog / News / Magazine Post listings, author archives, category filtering Recent posts, popular content, related articles E-commerce / Online Store Product listings, cart logic, order processing Inventory management, payment integration Business / Portfolio / Agency Service pages, team members, case studies Testimonials, project galleries Catalog / Directory / Listings Brand hierarchies, category filters Advanced search, sorting, pagination Generic / Mixed Content General purpose patterns for any site type Features Overview Always Exported (Core) ✅ Complete page tree structure ✅ All templates with field definitions ✅ Site configuration and settings ✅ Installed modules list ✅ Custom Page classes ✅ README with complete documentation ✅ SKILL.md for AI agents Optional (Configurable) ⚙️ Content samples (1-10 per template) ⚙️ API JSON schemas ⚙️ URL routing structure ⚙️ Performance metrics ⚙️ Code snippets library ⚙️ AI prompt templates ⚙️ Field definitions metadata Advanced Settings Auto-update on template/field changes Custom export path (supports absolute paths) Maximum tree depth (3-20 levels) JSON children limit (prevent huge files) Compact mode for large lists Custom AI instructions CSS framework detection (or manual override) Why TOON Format? TOON is specifically designed for AI prompts. Here's the difference: JSON (verbose): { "products": [ {"id": 1, "title": "Dark Chocolate", "price": 12.99}, {"id": 2, "title": "Milk Chocolate", "price": 9.99} ] } TOON (compact): products[2]{id,title,price}: 1,Dark Chocolate,12.99 2,Milk Chocolate,9.99 Same data, 50% fewer tokens! Use Cases 🤖 AI-Assisted Development Upload your site context to Claude/ChatGPT and get code that follows your exact patterns 🤖 AI Coding Agents Claude Code, Cursor, Windsurf can export and query your site via CLI 📚 Developer Onboarding New team members get complete site documentation instantly 🔄 Site Migration Export complete site structure for documentation or migration planning 📖 Code Standards Maintain consistency across your team with AI that knows your patterns 💰 Cost Optimization Reduce AI API costs by 30-60% with TOON format 🔁 Session Continuity Maintain context between AI coding sessions with project-summary.md API Variable In your ProcessWire code: // Get Context module instance $context = wire('context'); // Programmatic export $context->executeExport(); // Get export path $path = $context->getContextPath(); Links GitHub: https://github.com/mxmsmnv/Context TOON Format Spec: https://toonformat.dev Screenshots Example Workflow Export your site Click one button or run php index.php --context-export Upload to AI Upload .toon files to Claude/ChatGPT for maximum efficiency Build features faster AI knows your exact site structure, templates, and patterns Save money Use 30-60% fewer tokens on every AI interaction Perfect for ProcessWire developers who use AI coding assistants! The TOON format support makes it significantly more cost-effective to work with Claude, ChatGPT, and similar tools. Now with CLI support for seamless AI agent integration! Questions? Suggestions? Let me know! 🚀
  10. Hi, Are we the only ones who are running into this error during Updates and Installations of TracyDebugger? It is definitely a new error. Right now I cannot verify, but I want to say that I have seen it across various hosting environments. (I just ignored it before, because they were updates. Now I am trying to create a new installation. PW: 3.0.253 Tracey: latest from Git
  11. Hi everyone, Most project management tools are generic. Verk is built specifically around ProcessWire's data model — tasks link directly to PW pages, the calendar reads real page date fields, and content audits run PW selectors. Everything stays inside your install. GitHub: https://github.com/mxmsmnv/Verk Why Verk? Verk means "work" or "task" in Icelandic and Swedish. Short, abstract, and fitting for a tool built around getting things done inside ProcessWire. It follows the same naming approach as other modules in this series — Arbor, Ichiban, Collections — names that mean something without being literal. Screenshots: What it does Dashboard — open tasks, upcoming publications, audit alerts, and active sprint planning Tasks — create/assign tasks linked to specific PW pages; one click opens the page editor directly Calendar — month, week, and quarter views for page publications and task due dates Content Audit — run PW selectors with dot-notation field checks to find missing content Knowledge Base — rich editorial notes organized by category, searchable and exportable Sprints — sprint planning, quarter grouping, task assignment, DOCX export, and progress tracking Key details: Tasks store page_id — page data lives in PW, never duplicated Page Editor Widget injected via hookAfter('ProcessPageEdit::buildForm') — no template files modified Audit to tasks — bulk-create tasks from audit results with page context prefilled Rich text via TinyMCE when InputfieldTinyMCE is installed DOCX exports for task lists, notes, sprints, and knowledge base Return-aware forms — create/edit flows preserve filtered list URLs Requirements: ProcessWire 3.0.200+, PHP 8.0+ MIT License.
  12. Hi everyone! I am currently developing a new module for a client project and wanted to quickly reach out to see if there is broader interest in the community for a solution like this. The Use Case My client needed an appointment booking system similar to "Calendly". However, they had specific requirements: Zero external dependencies: No third-party SaaS for GDPR/DSGVO compliance and to avoid monthly fees. Full Design Control: It had to fit seamlessly into their custom design. Lightweight: No heavy bloat. The Solution: WireBooking is a native ProcessWire module that handles appointment slots and bookings using standard ProcessWire pages. Current Features: Frontend Wizard: An interactive, step-by-step booking process built with AlpineJS and Tailwind CSS. Native Storage: Bookings are saved as standard ProcessWire pages (booking-entry), allowing you to use the full power of PW selectors and hooks. Backend Management: Simple interface using the native ProcessWire Admin Theme (UIkit) to view bookings. Notifications: Sends confirmation emails to the customer and admin, including generated .ics calendar files for Outlook/Apple/Google Calendar. Availability Management: Manually block specific time slots or entire date ranges via the module settings. AJAX Driven: Dynamically loads available slots via JSON to keep the initial page load light. The "Catch" (Requirements) To keep the module lightweight and modern, it is opinionated regarding the frontend stack. It assumes you are already using (or are willing to include): Tailwind CSS (Utility classes) for the styling. Usage Example: Using it in a template is extremely simple: <?php echo $modules->get('WireBooking')->renderWizard(); ?> I need your feedback! The module is currently functional for this specific use case (Consultants/Service Providers). Before I invest time into generalizing it for a public release on the modules directory, I have two questions for you: Is this something you would use? Is there a need for a native "Calendly" alternative? Is the dependency on Tailwind a dealbreaker? Since the markup relies on Tailwind utility classes, it might be hard to style if you use Bootstrap or custom CSS. Looking forward to your thoughts and suggestions! Cheers, Markus GitHub: https://github.com/markusthomas/WireBooking
  13. WireWall 1.6.0 Released: Traffic History, AI-Ready Logs, and Dashboard Redesign Hi everyone, I’ve released WireWall 1.6.0, a new update for the ProcessWire firewall/security module. This release focuses on better traffic visibility, AI-assisted analysis, and a cleaner admin dashboard. What’s new AI-friendly traffic history WireWall can now save public request history as daily JSONL files: /site/assets/WireWall/traffic/traffic-YYYY-MM-DD.jsonl Each row contains structured request data such as: time allowed / blocked status block reason IP country city / region when available ASN method URL path and query referer User-Agent selected request headers This is separate from the normal ProcessWire log and is intended for later traffic analysis, including feeding recent traffic into AI tools. New setting A new option was added: Save Traffic History It is enabled by default and can be managed from the WireWall module settings. Dashboard redesign The Admin > Setup > WireWall dashboard has been redesigned with: clearer status header protection/logging indicators improved KPI cards better active bans view cleaner top reasons/countries/IPs sections more readable recent events table traffic history status and path display Agent-readable documentation This release also adds AGENTS.md, describing how AI agents and Olivia-style assistants should safely work with the module, including configuration keys, safe/risky operations, and website blueprint guidance. Version Current version: 1.6.0 Release: https://github.com/mxmsmnv/WireWall/releases/tag/v1.6.0 Repository: https://github.com/mxmsmnv/WireWall Feedback, bug reports, and configuration ideas are very welcome.
  14. This week we have ProcessWire 3.0.266 on the dev branch. The focus of this version has primarily been on expanding our documentation tools and API.md documentation files. As part of the process, WireTests files are added for each documented class. In addition, the WireApiDocs class got several major upgrades, plus its own documentation file: https://processwire.com/api/ref/wire-api-docs/ Other classes that gained custom API.md documentation and tests files this week were: Fieldtype: https://processwire.com/api/ref/fieldtype/ Selectors and Selector: https://processwire.com/api/ref/selectors/ Pages Versions: https://processwire.com/api/ref/pages-versions/ Wire Markup Regions: https://processwire.com/api/ref/wire-markup-regions/ Wire Text Tools: https://processwire.com/api/ref/wire-text-tools/ Wire Random: https://processwire.com/api/ref/wire-random/ Wire API Docs: https://processwire.com/api/ref/wire-api-docs/ The Fieldtype API.md was written by Claude Sonnet, Selectors/Selector was written by Claude Opus, PagesVersions was written by Kimi K2.7 and the rest were written by MiMo Pro. Each goes through multiple rounds of proofreading and testing. Proofreading is either done by GPT 5.5 or Claude Sonnet. Following that, GPT 5.5 builds tests for the class using the WireTests framework. After running tests, we find items to fix either in the API.md or the core. Then I do a round of proofreading and edits. Finally, both the class API.md file and the tests are committed to the core. At this point, most of the major classes in ProcessWire have their own API.md documentation files and tests, so now we're focused on some of the more specific tools and classes. I also wanted to mention that the Modules class got some major CLI improvements. Here's the full CLI command set available for the $modules API now: Modules ======= php index.php modules list [site|core] List installed modules, optionally limited to site or core modules php index.php modules unlist [site|core] List uninstalled modules, optionally limited to site or core modules php index.php modules info <name> [property] Get JSON of all info for module or optionally info property php index.php modules install <name> Install module php index.php modules uninstall <name> Uninstall module php index.php modules exists <name> Does given class name resolve to a module? (Yes/No) php index.php modules installed <name> Is module installed? (Yes/No) php index.php modules config <name> Get configuration data for module as JSON php index.php modules config <name> <property> Get value for property in module config php index.php modules dir <name> Query ProcessWire modules directory for module info php index.php modules updates [name] List available updates for installed site modules, or check one module php index.php modules download <name> [--install] Download module from PW modules directory (+ optionally install) php index.php modules download <url> [--install] Download module ZIP file from https URL (+ optionally install) php index.php modules update <name> [--force] Download and apply an available module update php index.php modules delete <name> Delete/erase uninstalled module from file system Optionally append --json to any of the above commands for more verbose JSON output While I'm posting CLI commands, here's the full command set for the updated WireApiDocs class: WireApiDocs =========== php index.php docs list List classes with API.md docs php index.php docs list 'Class*' List classes matches wildcard pattern php index.php docs list-verbose List classes with API.md docs in verbose mode php index.php docs list-verbose 'Class*' List classes matching pattern in verbose mode php index.php docs get <class> Get API docs for given class php index.php docs toc <class> Get table of contents for given class php index.php docs chapter <class> <num> Get body for given class and chapter number php index.php docs chapter <class> 'Title' Get body for given class and chapter title php index.php docs methods <class> Get public methods for given class (* prefix = hookable) php index.php docs method <class> <method> Get details for a single method (JSON only) php index.php docs classinfo <class> Get class info: parent, interfaces, traits php index.php docs constants <class> Get public constants for a class php index.php docs properties <class> Get @property annotations for a class php index.php docs groups <class> Get #pw-summary-[group] descriptions for a class php index.php docs vars List all API variables and the classes they represent WireApiDocs commands return JSON by default. To make command return plain text (not JSON), append `-text` to the command name, i.e. `list-text` See the dev branch commit log for additional core updates this week: https://github.com/processwire/processwire/commits/dev/. If using AgentTools, grab this week's new version too. More next week. Thanks for reading and have a great weekend!
  15. Hello everyone, I have been working on PWGermanShop, a comprehensive shop system built specifically for ProcessWire to address the regulatory and functional requirements of the German market. The system is nearing its final stages, and I am now looking for a small group of testers to help gather real-world feedback before a wider release. Since the ProcessWire forum is international, I am writing this post in English. However, please note that both the system and its documentation are currently only available in German, as the project is tailored to the DACH region. What is PWGermanShop? PWGermanShop is designed to handle the typical workflows and legal requirements of German e-commerce setups within ProcessWire. You can read through the documentation here to see how it works: 👉 https://mholte.de/docs/PWGermanShop/ How to participate in the test: The system is currently not publicly downloadable. I would like to share the installation files individually with interested testers to ensure a structured feedback process. If you are a ProcessWire developer building sites for the German-speaking market and would like to test the system: Please read the documentation to see if it fits your general requirements. Reply to this thread or send me a private message (PM) if you would like to participate. I will then send you the download link and instructions on how to install it. What kind of feedback is helpful? Is the setup and configuration process logical? Does the documentation cover all the steps clearly? Are there any bugs or edge cases you encounter during your tests? Thank you very much for your interest and support. I look forward to your feedback and to collaborating with some of you! Best regards
  16. I've been doing some testing with Agent Tools. My setup is MAMP Pro (PHP 8.3.30), using OpenAI (GPT-5). While I can see responses in the Conversation History, every request initially results in an Error 500. Only after reloading the page, I can return to Engineer tab and then see the response in the Conversation History. I can't figure out why this is happening as there are no errors logged at all, neither in the PHP / Apache logs. The only error I saw logged was this from the installation: files‑errors 2026‑06‑10 14:53:21 admin https://mysite.local/admin/module/edit?name=AgentTools filePutContents: Unable to write: [redacted]/site/assets/at/jobs/failed/.htaccess files‑errors 2026‑06‑10 14:53:21 admin https://mysite.local/admin/module/edit?name=AgentTools mkdir: Unable to mkdir [redacted]/site/assets/at/jobs/failed/ files‑errors 2026‑06‑10 14:53:21 admin https://mysite.local/admin/module/edit?name=AgentTools filePutContents: Unable to write: [redacted]/site/assets/at/jobs/done/.htaccess files‑errors 2026‑06‑10 14:53:21 admin https://mysite.local/admin/module/edit?name=AgentTools mkdir: Unable to mkdir [redacted]/site/assets/at/jobs/done/ files‑errors 2026‑06‑10 14:53:21 admin https://mysite.local/admin/module/edit?name=AgentTools filePutContents: Unable to write: [redacted]/site/assets/at/jobs/running/.htaccess files‑errors 2026‑06‑10 14:53:21 admin https://mysite.local/admin/module/edit?name=AgentTools mkdir: Unable to mkdir [redacted]/site/assets/at/jobs/running/ files‑errors 2026‑06‑10 14:53:21 admin https://mysite.local/admin/module/edit?name=AgentTools filePutContents: Unable to write: [redacted]/site/assets/at/jobs/pending/.htaccess files‑errors 2026‑06‑10 14:53:21 admin https://mysite.local/admin/module/edit?name=AgentTools mkdir: Unable to mkdir [redacted]/site/assets/at/jobs/pending/ ...but these folders have in fact been created: PW Debug mode is on, and so is Tracy. Any suggestions as to how to get beyond this point?
  17. Hi all — we're putting this one up as a public beta and looking for feedback before we tag a stable release. How it started. Over the past months we've been moving an old blog into a fresh PW site using our own SiteSync module and a Claude Code agent doing most of the migration grunt work. At some point the blog owner mentioned, in that very offhand way clients do, "hey, an image search would be nice." It was Saturday afternoon, so we let the agent build a prototype, pushed it through SiteSync, tested it on the phone an hour later. Worked great. Search results were… not great. But the search wasn't the problem – the underlying data was. Thousands of imported images, almost no descriptions, no tags, no nothing. So we needed a way to retroactively caption and tag a few thousand images without clicking through hundreds of page edits one by one. Since PW (rightly) attaches images to the pages they belong to, we needed a tool that reaches across the whole install at once and – crucially – can edit metadata in bulk. Why not the existing modules? We looked at the two obvious candidates: Media Manager by @kongondo – great if you're starting fresh and want a central media hub. But it's its own storage layer: you upload INTO Media Manager, editors pick FROM Media Manager. Images already sitting on per-page image fields stay invisible to it. Also commercial. MediaLibrary by @BitPoet – adds a MediaLibrary template with its own MediaImages / MediaFiles fields plus a CKEditor picker. Same pattern: a separate page hierarchy you migrate media into. Both are well-designed for "we want a central media model from day one." Neither helps you when the media is already scattered across lead_image, body_images, gallery, images_in_some_repeater etc. Migrating that into a different storage layer would have broken the original page model the blog depends on. So we built Image Library: a Process module that does nothing to your data – it just surfaces a cross-site table view of everything that's already there, with serious bulk editing on top. The bulk-edit part – the reason this module exists. Selection as a paintbrush. You tick N rows across any pages, templates and image fields. Then you edit a cell on ANY of those rows — the popup gains an Add / Replace mode picker (tags additionally offer Remove) and the value gets broadcast to the entire selection in one server round. Same row applies to description, tags, every custom subfield, AND the filename (with placeholders: (n), (n2)..(n5) padded counters, (N) total, (t) page title, (d) date, (p) page name, (f) field name → e.g. rename 200 selected files to event-2025-(n3).jpg). Same row applies to delete (one trash click, whole selection gone behind one confirm dialog with a where-used preflight – see below). Edits that push a row OUT of the active filter ("missing tags" → tag assigned → row no longer matches) fade out and drop from the table; counters auto-decrement. Other highlights: One sortable, paginated, bookmarkable table across every FieldtypeImage field on every page on every template (with config-side blacklists). Inline edit per cell – multilang-aware: language tabs in the popup, all languages committed in one save. Typed widgets per custom subfield: checkbox, date, integer, options (single + multi), and FieldtypePage rendered through PW's actually configured Inputfield (PageAutocomplete / PageListSelect / ASMSelect / whatever the field uses) — no re-implementation. Replace image in place (drag-drop or upload icon) – basename stays, variations regen. Renaming an image in the library instantly rewrites every CKEditor/TinyMCE embed of that file across the site — original and all variations, in every language — so links never break, and a summary dialog shows which pages were updated. Delete with where-used preflight: dialog scans every Textarea via $pages->findIDs("field%='/pid/stem.', include=all") and lists the pages where the image is still embedded in rich text – CKEditor + TinyMCE both, multilang-aware, with direct edit links so you can fix embeds before deleting. JSON / CSV export + import for offline metadata work – hand a CSV to a copywriter or feed it to your agent, get it back, import it. View prefs (columns, page size, bookmarks) live in $user->meta, cross-device. Status. v0.54.x – public beta. Module + docs (EN + DE concept) at GitHub or the Modules Directory Feedback welcome – especially edge cases we haven't seen yet (weird Fieldtype combos in custom-field templates, ProFields, Repeaters / RepeaterMatrix nesting). And if you've got a use case the current feature set doesn't cover, let us know. Cheers, Mike
  18. I've been meaning to revise PageimageSrcset for a while now, to remove some features that I felt were unnecessary and to implement a better rendering strategy. The result is PageimageSource. What does it do? It provides a configurable srcset method/property for Pageimage It allows WebP to be enabled for images it generates. It allows Pageimage:render() to return a <picture> element It provides a Textformatter that replaces <img> elements with the output of Pageimage:render() Although it is based on a current module, this should still be considered beta and not used in production without a prior development stage. Here's the README: PageimageSource Extends Pageimage with a srcset property/method plus additional rendering options. Overview The main purpose of this module is to make srcset implementation as simple as possible in your template code. For an introduction to srcset, please read this Mozilla article about responsive images. Installation Download the zip file at Github or clone the repo into your site/modules directory. If you downloaded the zip file, extract it in your sites/modules directory. In your admin, go to Modules > Refresh, then Modules > New, then click on the Install button for this module. ProcessWire >= 3.0.165 and PHP >= 7.3 are required to use this module. Configuration To configure this module, go to Modules > Configure > PageimageSource. Default Set Rules These are the default set rules that will be used when none are specified, e.g. when calling the property: $image->srcset. Each set rule should be entered on a new line, in the format {width}x{height} {inherentwidth}w|{resolution}x. Not all arguments are required - you will probably find that specifying the width is sufficient for most cases. Here's a few examples of valid set rules and the sets they generate: Set Rule Set Generated Arguments Used 320 image.320x0-srcset.jpg 320w {width} 480x540 image.480x540-srcset.jpg 480w {width}x{height} 640x480 768w image.640x480-srcset.jpg 768w {width}x{height} {inherentwidth}w 2048 2x image.2048x0-srcset.jpg 2x {width} {resolution}x How you configure your rules is dependent on the needs of the site you are developing; there are no prescriptive rules that will meet the needs of most situations. This article gives a good overview of some of the things to consider. When you save your rules, a preview of the sets generated and an equivalent method call will be displayed to the right. Invalid rules will not be used, and you will be notified of this. WebP If enabled, WebP versions of the image and srcset variations will be generated and these will be returned by Pageimage::srcset(). As with the default implementation, the image with the smaller file size is returned. In most cases this is the WebP version, but sometimes can be the source. Make sure to experiment with the quality setting to find a value you find suitable. The default value of 90 is fine, but it is possible that lower values will give you excellent kB savings with little change in overall quality. For more information on WebP implementation please read the blog posts on the ProcessWire website. Rendering These settings control how the output of Pageimage::render() is modified. Use Lazy Loading? When enabled this adds loading="lazy" to the <img> attributes. It is useful to have this on by default, and you can always override it in the options for a specific image. Use the <picture> element? When enabled, the <img> element is wrapped in a <picture> element and <source> elements for original and WebP variations are provided. This requires WebP to be enabled. For more information on what this does, have a look at the examples in Pageimage::render() below. Remove Variations If checked, the image variations generated by this module are cleared on Submit. On large sites, this may take a while. It makes sense to run this after you have made changes to the set rules. Please note that although the module will generate WebP versions of all images if enabled, it will only remove the variations with the 'srcset' suffix. Usage Pageimage::srcset() // The property, which uses the set rules in the module configuration $srcset = $image->srcset; // A method call, using a set rules string // Delimiting with a newline (\n) would also work, but not as readable $srcset = $image->srcset('320, 480, 640x480 768w, 1240, 2048 2x'); // The same as above but using an indexed/sequential array $srcset = $image->srcset([ '320', '480', '640x480 768w', '1240', '2048 2x', ]); // The same as above but using an associative array // No rule checking is performed $srcset = $image->srcset([ '320w' => [320], '480w' => [480], '768w' => [640, 480], '1240w' => [1240], '2x' => [2048], ]); // The set rules above are a demonstration, not a recommendation! Image variations are only created for set rules which require a smaller image than the Pageimage itself. This may still result in a lot of images being generated. If you have limited storage, please use this module wisely. Pageimage::render() This module extends the options available to this method with: srcset: When the module is installed, this will always be added, unless set to false. Any values in the formats described above can be passed. sizes: If no sizes are specified, a default of 100vw is assumed. lazy: Pass true to add loading=lazy, otherwise false to disable if enabled in the module configuration. picture: Pass true to use the <picture> element, otherwise false to disable if enabled in the module configuration. Please refer to the API Reference for more information about this method. // Render an image using the default set rules // WebP and lazy loading are enabled, and example output is given for <picture> disabled and enabled echo $image->render(); // <img src='image.webp' alt='' srcset='image.jpg...' sizes='100vw' loading='lazy'> /* <picture> <source srcset="image.webp..." sizes="100vw" type="image/webp"> <source srcset="image.jpg..." sizes="100vw" type="image/jpeg"> <img src="image.jpg" alt="" loading="lazy"> </picture> */ // Render an image using custom set rules echo $image->render(['srcset' => '480, 1240x640']); // <img src='image.webp' alt='' srcset='image.480x0-srcset.webp 480w, image.1240x640-srcset.webp 1240w' sizes='100vw' loading='lazy'> /* <picture> <source srcset="image.480x0-srcset.webp 480w, image.1240x640-srcset.webp 1240w" sizes="100vw" type="image/webp"> <source srcset="image.480x0-srcset.jpg 480w, image.1240x640-srcset.jpg 1240w" sizes="100vw" type="image/jpeg"> <img src="image.jpg" alt="" loading="lazy"> </picture> */ // Render an image using custom set rules and sizes // Also use the `markup` argument // Also disable lazy loading // In this example the original jpg is smaller than the webp version echo $image->render('<img class="image" src="{url}" alt="Image">', [ 'srcset' => '480, 1240', 'sizes' => '(min-width: 1240px) 50vw', 'lazy' => false, ]); // <img class='image' src='image.jpg' alt='Image' srcset='image.480x0-srcset.webp 480w, image.1240x0-srcset.webp 1240w' sizes='(min-width: 1240px) 50vw'> /* <picture> <source srcset="image.480x0-srcset.webp 480w, image.1240x0-srcset.webp 1240w" sizes="(min-width: 1240px) 50vw" type="image/webp"> <source srcset="image.480x0-srcset.jpg 480w, image.1240x0-srcset.jpg 1240w" sizes="(min-width: 1240px) 50vw" type="image/jpeg"> <img class='image' src='image.jpg' alt='Image'> </picture> */ // Render an image using custom set rules and sizes // These rules will render 'portrait' versions of the image for tablet and mobile // Note the advanced use of the `srcset` option passing both `rules` and image `options` // WebP is disabled // Picture is disabled echo $image->render([ 'srcset' => [ 'rules' => '320x569, 640x1138, 768x1365, 1024, 1366, 1600, 1920', 'options' => [ 'upscaling' => true, 'hidpi' => true, ], ], 'sizes' => '(orientation: portrait) and (max-width: 640px) 50vw', 'picture' => false, ]); // <img src='image.jpg' alt='' srcset='image.320x569-srcset-hidpi.jpg 320w, image.640x1138-srcset-hidpi.jpg 640w, image.768x1365-srcset-hidpi.jpg 768w, image.1024x0-srcset-hidpi.jpg 1024w, image.1366x0-srcset-hidpi.jpg 1366w, image.1600x0-srcset-hidpi.jpg 1600w, image.jpg 1920w' sizes='(orientation: portrait) and (max-width: 768px) 50vw' loading="lazy"> TextformatterPageimageSource Bundled with this module is a Textformatter largely based on TextformatterWebpImages by Ryan Cramer. When applied to a field, it searches for <img> elements and replaces them with the default output of Pageimage::render() for each image/image variation. Assuming a default set of 480, 960 and lazy loading enabled, here are some examples of what would be returned: Example <figure class="align_right hidpi"> <a href="/site/assets/files/1/example.jpg"> <img alt="" src="/site/assets/files/1/example.300x0-is-hidpi.jpg" width="300" /> </a> </figure> WebP enabled <figure class="align_right hidpi"> <a href="/site/assets/files/1/example.jpg"> <img alt="" src="/site/assets/files/1/example.300x0-is-hidpi.webp" width="300" srcset="/site/assets/files/1/example.300x0-is-hidpi.webp 480w" sizes="100vw" loading="lazy" /> </a> </figure> <picture> enabled <figure class="align_right hidpi"> <a href="/site/assets/files/1/example.jpg"> <picture> <source srcset="/site/assets/files/1/example.300x0-is-hidpi.webp 480w" sizes="100vw" type="image/webp"> <source srcset="/site/assets/files/1/example.300x0-is-hidpi.jpg 480w" sizes="100vw" type="image/jpeg"> <img alt="" src="/site/assets/files/1/example.300x0-is-hidpi.jpg" width="300" loading="lazy" /> </picture> </a> </figure> Because the variation is small - 300px wide - the srcset only returns the source image variation at the lowest set width (480w). If the source image was > 1000px wide, there would be a variation at both 480w and 960w. PageimageSrcset This module is built upon work done for PageimageSrcset, which can be considered a first iteration of this module, and is now deprecated. Migration PageimageSource is a simplified version of PageimageSrcset with a different approach to rendering. Most of the features of the old module have been removed. If you were just using $image->srcset(), migration should be possible, as this functionality is essentially the same albeit with some improvements to image variation generation.
  19. hi @BrendonKoz exaclty like you said in your answers, the first thing i thought about was all those directories i use outside pw /site one for special cron jobs (not lazy ones :)) downloadable files and so on without any problem... but you're right, first thing to check is if the host allows htacces protection (if not, time to change because it would sound a bit prehistoric 😄 ) afterwards, maybe the url he gives as pw htaccess prevents direct access to php files for exemple that why my second thought was to exclude the directory from pw htaccess rules and then put his own ones in the directory htaccess and see what happens, it's a bit harsh but also a simple debug attempt 🙂 have a nice day
  20. @adrian, its very simpel activating columns and reordering them, on desktop its simply drag and drop, on mobile you got arrows. The checkboxes are shown only when active, clicking on the column name (or row) checks/unchecks. Bildschirmaufnahme 2026-06-19 um 20.08.51.mov Download button: I'm not sure this one fits the concept, to be honest. The library is meant as a central audit/management view of images that already live in your fields — where they're used, duplicates, inline metadata edits — and the original files are already reachable through their normal URLs (and via the page editor). A "download" action sort of cuts across that purpose, so before we add UI for it I'd rather understand what you're actually after. What's the use case? A few things it could mean, and they'd point at different solutions: grabbing originals to re-use elsewhere on the site → that's really what Insert/Choose from library already covers pulling files out for offline backup / handing to a client → more of an export concern than a per-thumbnail button just quick access to the full-size original → a click on the thumb takes one to the file and all variations. If you tell me the scenario, I can figure out whether it belongs here at all, or whether there's a better-fitting way to get you there. Replace and extensions: That one's intentional, though I can see why it feels off. Replace deliberately keeps the exact same filename — and therefore the same URL — so that every existing reference to the image (field relations, rich-text embeds, the "Used in" entries) keeps working untouched. Since the extension is part of the filename, allowing photo.jpg → photo.png would actually change the URL and silently break all those references. So Replace pins the format on purpose; it's a "swap the bytes behind this exact file" operation, not a "change the format" one. Our daily use case is replacing unretouched layout files with the finished images. If you genuinely want a different format, deleting the old image and uploading the new one is the right path — that gives you a new filename/URL, which is what a format change really is under the hood. The field's allowed-extensions setting is a separate thing (it governs new uploads); Replace is intentionally stricter than that. I could probably make the error message clearer about why, though — point taken. Cheers, Mike
  21. @adrian reported an issue where the module is generating entries in the files-errors log. We see this too on sites that are using the module. It is intermittent, but when it happens there are normally a few entries at the same time: rename: Rename to pathname ($newName) that already exists: /site/assets/files/8936/thumbnail_1000_x_1000_px_32.768x635-srcset-hidpi.webp rename: Rename to pathname ($newName) that already exists: /site/assets/files/8936/thumbnail_1000_x_1000_px_32.768x635-srcset-hidpi.jpg rename: Rename to pathname ($newName) that already exists: /site/assets/files/8936/thumbnail_1000_x_1000_px_32.300x600-srcset-hidpi.webp rename: Rename to pathname ($newName) that already exists: /site/assets/files/8936/thumbnail_1000_x_1000_px_32.300x600-srcset-hidpi.jpg rename: Rename to pathname ($newName) that already exists: /site/assets/files/8936/thumbnail_1000_x_1000_px_32.265x530-srcset-hidpi.webp rename: Rename to pathname ($newName) that already exists: /site/assets/files/8936/thumbnail_1000_x_1000_px_32.265x530-srcset-hidpi.jpg I've taken a look but can't see what is causing it, and reviewing Pageimage::size() suggests that it shouldn't be happening, as this checks whether the file exists before calling WireFileTools::rename(), where the error log originates. The best I can come up with is that because the module is (usually) passing webpAdd as an option to its width() / height() / size() calls, this sets forceNew to true, and a second request happens before the variation generation completes on the first request, and it is this second request that ends up generating the log entry (the first request completes between the second one checking and then calling rename). I'm not sure if that's it though, I could easily be missing something. @ryan do you have any idea what might be happening here? Is this an error you've seen in other places? EDIT: Adrian has consulted Claude and posted the result in the GitHub issue thread here: https://github.com/nbcommunication/PageimageSource/issues/8#issuecomment-4612395594. It does suggest a race condition which would need to be handled by a change to Pageimage::size(). Cheers, Chris
  22. Hi everyone, I’m preparing a new ProcessWire module for release: Panorama. Panorama is a media audit and maintenance toolkit for ProcessWire images and files. It is built for sites where media is spread across many templates, repeaters, galleries and file fields, and where you need one place to understand what is stored, where it is used, what can be cleaned up and what needs attention. What it does Media dashboard with totals, disk usage, average size, recent uploads and largest files. Breakdown by file type, field, page and template. Visual Explorer for browsing media by gallery, page or template. Detail drawer with owner page, template, field, dimensions, file size and image variations. Duplicate finder with background scan, visual cards and reclaimable space estimates. Alt text audit for images missing descriptions. Cleanup tools for broken references, orphaned originals and orphaned variations. Background image variation warmup. Bulk actions for selected media. CSV export. Support for Repeaters, Repeater Matrix and FieldsetPage ownership where possible. The heavier thumbnail-based sections load in the background, so the main admin page should stay responsive even on media-heavy sites. Requirements ProcessWire 3.0.227+ PHP 8.3+ Repository GitHub: https://github.com/mxmsmnv/Panorama
  23. Hey everyone, on a recent client project we had to deal with a large number of Markdown files that needed to end up as regular HTML content on ProcessWire pages. Converting them manually or piping them through external tools wasn't an option – too many files, too tedious, and the content had to be stored as actual HTML in rich textfields, not just formatted at runtime. So we built a small module that handles this directly inside ProcessWire. How it works The module creates a file upload field (md_import_files) and a Repeater field (md_import_items) with a standard title field and a richtext body field (md_import_body) inside. The body field automatically uses TinyMCE if installed, otherwise CKEditor. You add both fields (md_import_files,md_import_items) to any template, upload your .md files, hit save – each file gets converted to HTML via PW's core TextformatterMarkdownExtra and stored as a separate Repeater item. The source filename goes into the items title, processed files are removed from the upload automatically. Template output The Repeater items are regular PW pages, so output is straightforward: foreach ($page->md_import_items as $item) { echo "<section>"; echo "<h2>{$item->title}</h2>"; echo "<div>{$item->md_import_body}</div>"; echo "</section>"; } Tag mappings One thing we needed right away: control over how certain Markdown elements end up in HTML. For example, #headings in Markdown become <h1> – but on most websites <h1> is reserved for the page title. The module has a simple config (Modules → Configure → Markdown Importer) where you define tag mappings, one per line: h1:h2 h2:h3 strong:b blockquote:aside hr:br This performs a simple 1:1 tag replacement after conversion, preserving all attributes. Works well for standalone or equivalent elements like headings, inline formatting, blockquotes, or void elements like hr:br. Note that it doesn't handle nested structures – mapping table:ul for example would only replace the outer <table> tag while leaving thead, tr, td etc. untouched. Requirements ProcessWire 3.0.0+ FieldtypeRepeater (core) TextformatterMarkdownExtra (core) GitHub: github.com/frameless-at/MarkdownImporter Modules Directory: https://processwire.com/modules/markdown-importer/ Happy to hear if anyone finds this useful or has suggestions for improvements. Cheers, Mike
      • 6
      • Like
      • Thanks
  24. Happy Friday, everyone. I'm starting this Friday with something I meant to do last Friday! The latest version of MediaHub (1.19.25) is now available, and thanks to our testers, we have improvements across the UI, module performance and some new features too. Existing Media hubbers: Download here New to hubbing: Read here Full changelog: Read here What's new and improved in 1.19.25... Upload screen refresh Uploading is one of the first things a new user will do, so the first impression should be positive, distraction-free and simple. But behind a screen that seemingly has 'just one job', people asked if they could organise their uploads from here. While organising uploaded assets within the Library is simple, being able to associate your uploads with your Collections and Labels from the upload screen will save you a lot of time and asset admin. An "Organise uploads" bar above the dropzone lets you assign Collections and Labels before the batch starts. If one doesn't exist yet, you can create it from here. A scrollable card queue replaces the old list. Each file shows a thumbnail or file-type icon, inline status, and a per-file progress bar. Oversized or unsupported files stage with a clear warning and are excluded from the upload. Inline filename editing on each card is possible before you upload. We'll introduce a table view shortly if you're uploading at scale and want to sort and filter at this point. Once your upload starts, you can see the progress of each file and a master progress bar. Custom fields on assets Adding custom fields to a MediaHub input field works the same way as the existing workflow. Should you wish, you can also assign custom fields to a master asset depending on your use case. You can assign custom fields to your master asset or just the MediaHub field on your page. They work indenpendently when you want, but also have a relationship with and inherit-with-override model. Inherit-with-override works the same way Title and Alt already do: The asset detail page (left) holds the canonical (library-level) value. Every reference inherits it by default. On a page, custom fields appear below Title, Filename, Description, and Tags. An editor can override the value for that one reference only. The override saves when the page saves, no separate save button A small reset control next to any overridden field lets you revert to the library value in one click On a MediaHub input field, a developer can choose to display custom fields in a different order than on the asset detail page Two tiers Some metadata belongs to the asset everywhere (a photographer credit, a licence URL). Other metadata belongs to how the asset is used in a specific field. Both are supported: Asset-level fields go on pkd-mediahub-asset. Master value plus per-reference override and reset Field-specific fields go on a template named mediahub-field-{fieldName} (mirrors ProcessWire's native pattern). These appear only in that field's drawer and are per-reference only, no library master I hadn't planned on allowing custom fields on the asset detail page, but it was straightforward once I added some of the standard text-based fields. It works in the same way you'd add a field to any template and doesn't even require the extra custom field to input field step (creating an extra fileless template). Anything on that asset template that isn’t one of MediaHub’s built-in fields: title, image, alt, labels, collections, and so on - is treated as yours. Should you wish to uninstall MediaHub, we have safeguards in place to keep your custom fields on your ProcessWire install, which is what I think you might want. The only real downside I have found so far is that custom fields on the master asset template show on every asset detail page, so a name like Photographer fits a photo but feels odd on a PDF or spreadsheet. What has worked for me is broader labels from the start (Source, Description). We plan to make this more asset-aware in a future release, but for now, name fields as if every asset type will see them, because they will. But, this is just a side note and doesn't affect input fields, which was the core feature and of the 1.19.25 release. Library thumbnails 1.19.25 takes a leaner approach to thumbnail generation and makes more effort to reuse thumbnails across the UI vs generating the full scope on upload and import. One preview at upload. Each image gets a single small proportional preview. That's 75% fewer auto-generated files at upload time. One library thumb per asset. Grid, Masonry, and List share one canonical thumbnail. CSS handles grid cropping. Built on first browse. The full library size is generated the first time you scroll an asset into view, not during upload. The upload preview is shown immediately as a placeholder so nothing looks broken while it's being prepared Import Existing Images and the asset picker use the same on-demand model. Bulk imports of existing assets from existing fields should feel noticeably lighter on disk and CPU. Library bulk actions and toolbar The search and filter area of the Library was cleaned up for consistency and clarity in advance of some architectural changes (more below) Selecting assets now swaps the breadcrumb row for a compact bulk action bar with actions for Collections, Labels, and Delete. There's a useful workflow change here: you can select assets first and then create and assign a collection in one step, rather than having to create the collection first. Library and picker consistency MediaHub looks like it has one central Library, but under the hood there are actually three slightly different versions of it: the main Library, the InputfieldMediaHub picker, and the TinyMCE picker. Over time I found that improvements made to the main Library were easy to overlook on the other two, since they didn't share any underlying code. To reduce that drift, 1.19.25 moves the toolbar, sidebar, filters, and tiles onto shared partials so all three surfaces stay aligned going forward. This isn't just a tidy-up under the hood either. It lightens the module overall, and it's what made it possible to introduce the Collections and Labels sidebar into Library screens that didn't have it before. Import page images The ability to import images from your existing fields was an early feature and has been in MediaHub since v1 1.19.25 gives it an overhaul. BTW the import Page Images button is optionally enabled in the field config so you can enable it on a field-by-field basis. Repeater and RepeaterMatrix support The scan now walks Repeater and RepeaterMatrix fields up to three levels deep. Results are grouped under breadcrumb headings so you can see exactly where each image came from. How matching works Each image on the page is scored against the whole Hub using four signals: filename stem file size dimensions and a perceptual hash (a 64-bit visual fingerprint that can match re-encoded or renamed copies). Each result gets a confidence badge: New - not currently in the Hub Exact match - identical file already in the Hub Likely match - looks like an asset already in the Hub Possible match - filename matches a Hub asset but the file content appears different Already added - already used in this field When a match is confirmed, MediaHub adds a reference to the existing asset rather than copying the file again. Hardening for large pagesThere's also longer scan and import time limits, JSON error handling, a 200-selection cap per request, and client-side checks so a timeout doesn't surface as a cryptic error. Import Page Images was one of MediaHub's earliest features, and I think there's more we can do here. The import modal in particular could use a bit more cleanup, so that's on the list. That's pretty much it. Thanks for reading and scrolling! MediaHub is currently available for single sites, developers of multiple sites and agencies. If you'd like to try it first, DM me. Have a great weekend, Peter
  25. Hey guys, first, ProcessWire is a great piece of software. Thanks for that and the great community behind that. So, i'm realy new to ProcessWire, but i will present you my first module for SEO- and performance optimizing: AIOM+ (All In One Minify). AIOM+ (All In One Minify) for CSS, LESS, JS and HTML AIOM+ (All In One Minify) is a module to easily improve the performance of your website. By a simple function call Stylesheets, LESS and Javascript files can be parsed, minimized and combined into one single file. This reduces the server requests, loading time and minimizes the traffic. In addition, the generated HTML source code can be minimized and all generated files can be loaded over a cookieless domain (domain sharding). Install AIOM+ Download current release (link below) Extract and copy the files for this module to /site/modules/AllInOneMinify/ Login to PW backend and go to Modules > Check for new modules Install Module > AIOM+ (All In One Minify) for CSS, LESS, JS and HTML Alternative in ProcessWire 2.4 Login to PW backend and go to Modules Click tab "new" and enter Module Class Name: "AllInOneMinify" Click "Download and Install" Features Combining stylesheets / LESS files or JavaScripts Minimize the combined files No change to the .htaccess necessary (except for the domain sharding) Server-side LESS parsing without plugins HTML source code minimization Cookieless domain / domain sharding Automatic cache management (With changes to the source file, the cache is rebuilt) Configurable via the backend Automatic rewriting the paths in the stylesheet and LESS files. No changes are needed Optional developer mode (combining, but no minimize and browser cache prevention) Clear the cache on the backend Conditional loading for CSS, LESS and JS (since Version 3.1.1) How to use Minimize multiple stylesheet or LESS files into one file. You can even mix stylesheet and LESS files in parsing and combining process! <link rel="stylesheet" href="<?php echo AIOM::CSS(array('css/file-1.css', 'css/file-2.less', 'css/file-3.css', 'css/file-4.less')); ?>"> Minimize multiple javascript files into one file. <script src="<?php echo AIOM::JS(array('js/file-1.js', 'js/file-2.js', 'js/file-3.js', 'js/file-4.js')); ?>"></script> Conditional loading (same with Javascripts) <?php $stylesheets = array('css/reset.css', 'css/main.less', array('loadOn' => 'id|template=1002|1004|sitemap', // PW API selector 'files' => array('css/special.css', 'css/special-theme.less'))); ?> <link rel="stylesheet" type="text/css" href="<?php echo AIOM::CSS($stylesheets); ?>" /> More Information, Documentation and Download AIOM+ in ProcessWire repository AIOM+ on GitHub So, I hope you can do something with this module. Dave
×
×
  • Create New...