Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation since 01/14/2026 in Posts

  1. As some of you might know from my monthly newsletter I have been struggling with how to proceed with my commercial modules. It's a long story, but last year I reached a point were something had to change. The main problem is that building and selling modules for ProcessWire has never been sustainable for me. Not even close. It has been a lot of work to build the shop. It has been a lot of work to provide proper docs. It has been a lot of work to create videos about the modules so that interested people can get an idea of my modules. That's fine. I knew it would probably not be easy. But I wanted to try ๐Ÿ™‚ You never know if you don't try. And I've had hope that it is possible. Unfortunately I don't have this hope any more and that's why I have to draw a line under it. That's also fine. I've learned a lot and I'm really thankful for anybody that has sent some Euros to a stranger that they have never met in person and that excludes any refund ๐Ÿ˜„ So for me the decision was taken. It took me quite some time to get there, but here we are. There was just one problem left: My clients. They have put trust in me and I didn't want to disappoint them. Just drawing a line might be a good solution for myself but might be a terrible solution for them (and their clients as well). Just not providing updates and keeping selling them is also not my style. With open sourcing my modules I try to find the best solution for everybody involved and I want to especially thank @FireWire for helping me get there ๐Ÿ™‚ What does that mean? I'm using my modules in many of my own projects, which means that I will likely keep them alive for some time. On the other hand I don't plan to develop a lot of websites any more and many modules are somewhat feature complete as @FireWire helped me to realise, so there are no bigger updates planned for any of my modules at this time. Also, none of my modules is tested with the new admin theme. If you want to help out on that front, I'll be happily merging PRs, but as I'm not using it myself I'm not going to fix any issues or adding support for it in my spare time. So if you want to keep using my modules: Go ahead and have fun! ๐Ÿ™‚ If you find the modules helpful it's always nice to let me know. Hope this is a good solution for everyone! Thx for reading and all the best.
    36 points
  2. I have never been loyal to tools for the sake of it. If something stops earning its keep, I move on. The reason I have stayed with ProcessWire for close to ten years is simple: it continues to make sense for how I work. I still look after sites I built many years ago, and most of them just run. No rewrites, no upgrade stress, no feeling that past work is a liability. The API has stayed stable, and when it has changed, it has been deliberate and predictable. That matters when you are responsible for client sites long-term. What really locked me in early on was the front-end freedom. PW never told me how a site should look or behave. It gave me solid building blocks and allowed me to choose. I can build very different sites without switching platforms or fighting opinionated defaults, and that freedom is something I value. The forum is another reason I am still here. You, the people in this community, take the time to understand a problem before jumping to solutions. That is very rare. The discussions are thoughtful, practical, and grounded in real experience, and I have learned a lot simply by reading how others approach things. And finally, trust. I trust ProcessWire not to chase trends simply for attention, and not to trade clarity or performance for fashion. Ten years on, it still feels like a system built by people who actually build websites. For me, that combination has been hard to beat.
    26 points
  3. Hi everyone, This module completely replaces the default ProcessWire image sizing engine with the powerful Intervention Image v3 library. The goal was to modernize how we handle images in ProcessWire, bringing in features like AVIF support, superior resizing quality, and strict aspect-ratio handling, while keeping the API compatible with what you already know. ๐Ÿš€ What does it do? Replacement: It hooks into Pageimage. You can keep using $image->width(300), $image->size(800, 600), or $image->crop(...) just like you always have. Modern Formats: Automatically handles WebP and AVIF generation. Smart Responsive Images: It introduces a configuration-based approach where you define Breakpoints, Grid Columns, and Resizing Factors. The module uses these settings to automatically calculate and generate the perfect srcset for your layouts. โœจ New Methods: render() and attrs() While standard methods work as expected, Iโ€™ve added/updated methods to handle modern HTML output: 1. $image->render(string $preset, array $options) This outputs the complete HTML tag. It automatically handles: The <img> tag with srcset and sizes. The <picture> tag with <source> elements if you have enabled extra formats (like AVIF/WebP) in the settings. Lazy Loading & LQIP: It automatically generates a Low Quality Image Placeholder (pixelated/blur effect) and applies a base64 background to the image tag for a smooth loading experience. // Example: Render a 'landscape' preset defined in module settings echo $page->image->render('landscape', ['class' => 'my-image']); 2. $image->attrs(string $preset, array $options) Perfect for developers who use template engines like Twig or Latte, or prefer full control over their HTML. This returns an array of attributes instead of an HTML string. $data = $page->image->attrs('landscape'); // Returns array like: // [ // 'src' => '...', // 'width' => 1200, // 'height' => 675, // 'srcset' => '...', // 'sources' => [ ... ], // Array for picture tag sources // 'style' => 'background-image: url(data:image...);', // LQIP Base64 // 'class' => 'iv-lazy ...' // ] โš™๏ธ Configuration Strategy Instead of hardcoding sizes in your templates, you configure your design tokens in the module settings: Breakpoints (e.g., 1200px) Aspect Ratios (e.g., 16:9) Grid Columns (e.g., 1-1, 1-2, 1-3) Factors (e.g., 0.5, 1, 1.5, 2 for Retina support) The module calculates the necessary image dimensions based on these combinations. If you request a specific aspect ratio, it ensures strict adherence to it, preventing 1px rounding errors. ๐Ÿ“ A Note on Documentation I wanted to get this into your hands as soon as possible, but due to a heavy workload, I haven't finished writing the detailed README.md yet. Currently, you can grab the code from GitHub (link below). I will submit this to the official ProcessWire Modules Directory after add some other features and after update readme.md Download / GitHub: GitHub Repo Iโ€™d love to hear your feedback and suggestions!
    26 points
  4. Everything you need to know about custom page classes, from beginner to advanced. You'll find time saving tips and tricks, pitfalls, best practices, and plenty of examples tooโ€” https://processwire.com/blog/posts/custom-page-classes/
    24 points
  5. Included are more than 70 issue fixes and 175 commits. Here weโ€™ll zoom in on the numerous new features and improvements to the core for one of our best new versions yet! https://processwire.com/blog/posts/pw-3.0.255/
    23 points
  6. Hey, everyone, here at frameless we frequently work with clients who already have a website but aren't happy with it and want us to rebuild it from scratch. Whenever possible, we use ProcessWire for new web projects โ€“ no surprise there, given the flexibility and clean API we all love. For smaller sites, migrating content is usually straightforward โ€“ a bit of copy/paste and you're done. But for larger projects with hundreds or thousands of records across multiple database tables, this quickly becomes tedious and error-prone. Over the years, we've written various import scripts and parsers to handle these migrations. We finally decided to clean them up and package everything into a proper module that we'd like to share with the community. Introducing: Data Migrator Data Migrator is a Process module that imports external data (SQL dumps, CSV, JSON, XML) directly into ProcessWire's page structure โ€“ including automatic creation of templates, fields, and even PHP template files. Key Features Multi-format support โ€“ Import from .sql, .csv, .json, and .xml files Automatic type detection โ€“ Recognizes emails, URLs, dates, booleans, integers, etc. and maps them to appropriate ProcessWire fieldtypes SQL schema parsing โ€“ Extracts column types from CREATE TABLE statements for better field mapping Foreign Key handling โ€“ Detects FK relationships and sorts tables by dependency order Dry Run mode โ€“ Preview exactly what will be created before committing anything Full Rollback โ€“ Undo an entire migration with one click (removes all created pages, templates, and fields) Template file generation โ€“ Automatically creates ready-to-use .php template files in /site/templates/ How it works Upload your data file (SQL dump, CSV, JSON, or XML) Review the analysis โ€“ the module shows detected tables, columns, suggested fieldtypes, and sample values Fine-tune if needed โ€“ override fieldtypes via dropdown, configure FK relationships Run a Dry Run to preview all changes Execute the migration โ€“ templates, fields, parent pages, and data pages are created automatically If something's wrong โ€“ hit Rollback to cleanly undo everything Requirements ProcessWire 3.0.0+ PHP 7.4+ Links GitHub: github.com/frameless-at/ProcessDataMigrator Modules Directory: /modules/process-data-migrator/ We've been using the methods and classes bundled in this module internally for a while now and it has saved us a lot of time on migration projects. We hope it's useful for others facing similar challenges. Feedback, bug reports, and feature requests are welcome! Cheers, Mike
    23 points
  7. Hi everyone, First of all I had no idea, which category would fit best ... I'd like to share a little tool I've been working on to make the initial setup of ProcessWire even faster, especially when working on remote servers without SSH access. What is it? kickstart.php is a modern, single-file installer/loader for ProcessWire. Instead of uploading thousands of files via FTP, you just upload this one file and it handles the rest. Key Features: Version Selection: Choose between the master (stable) or dev branch directly from GitHub. Smart Multi-Language: Built-in support for English, German, Spanish, and French (with automatic browser language detection). Modern UI: Built with Tailwind CSS, AlpineJS, and smooth animations using Anime.js. Pre-flight Checks: Automatically checks for PHP version requirements and prevents overwriting existing installations. Automatic Cleanup: Removes the downloaded ZIP archive and temporary folders after extraction. How to use it: Upload kickstart.php to your webroot. Open it in your browser. Choose your version and click install. Once finished, click the button to start the official ProcessWire installer. I hope some of you find this useful for your workflow! Feedback and suggestions are always welcome. Cheers, Markus kickstart.php Improved Version now available on GitHub: https://github.com/markusthomas/ProcessWireKickstart
    16 points
  8. We recently launched the digital home for the TECH.LAND Xperience, a cross-border innovation festival. The project required a robust system capable of handling complex schedules and providing a seamless, app-like user experience. Technical Stack & Advanced Techniques: ProcessWire CMS & RockMigrations: The flexible backbone for managing dynamic content. We used RockMigrations for a completely code-driven development workflow, ensuring that all fields, templates, and configurations are version-controlled and easily deployable. Modern Frontend Workflow: Built with RockFrontend and Vite, we utilized the Latte template engine for clean, secure, and maintainable markup. This setup allowed us to use a modern build pipeline with HMR (Hot Module Replacement) during development. Tailwind CSS & DaisyUI: For a rapid, modern, and futuristic UI. DaisyUI provided the foundation for complex UI components like the Side-Panel drawers. AJAX, Fetch API & HTMX Integration: To keep the user experience fluid, we implemented a decoupled approach for session and speaker details. Instead of traditional page reloads, content is fetched dynamically from dedicated ProcessWire endpoints (/ajax/speaker/, /ajax/event/). Interactivity with Alpine.js: We leveraged Alpine.js for lightweight frontend logic, managing the state of the program filters and the dynamic drawer UI without the overhead of a heavy framework. Dynamic Drawer UI: Speaker biographies and session details are presented in a modern Side-Panel component. This allows visitors to explore details without losing their position on the interactive timeline. Hash-URLs & Deep Linking: We implemented Hash-based URLs for the drawers. This ensures that every session and speaker has a unique, shareable link that opens the corresponding drawer automatically on page load, while also supporting the browser's "back" button functionality. Interactive Program Timeline: A high-performance schedule with four parallel stages. Modular Content with RockPageBuilder: For editorial flexibility, we used RockPageBuilder, allowing the team to create complex landing pages with modular, reusable components. Performance Optimization: Fast loading times were achieved through WebP delivery, lazy loading are integrated into our Vite build process (custom module). Key Modules used: RockMigrations: Code-first field and template management. RockFrontend: Vite integration and Latte support. RockPageBuilder: Modular content blocks for editors. SeoMaestro: Comprehensive SEO management. TracyDebugger: Indispensable for rapid development and debugging. Key Success Metrics: 5,000+ Visits shortly after launch. High Engagement: Seamless navigation through complex datasets with zero layout shifts. Editorial Efficiency: Automatic session-to-speaker assignment and drag-and-drop scheduling. complete case-study in german: Explosives Wachstum: รœber 5.000 Besucher fรผr die TECH.LAND Xperience kurz nach Launch Visit our website for more insights: dotnetic.de techland-xperience-dotnetic-referenz.mp4
    14 points
  9. Hi ProcessWire community! ๐Ÿ‘‹ I'm excited to share a new module I've been working on: TeleWire - a Telegram notifications module that brings instant messaging capabilities to your ProcessWire sites. The Problem with Current Notification Solutions After running several e-commerce sites and experimenting with different notification systems, I've encountered these recurring issues: ๐Ÿ“ง Email (SMTP/WireMail): Requires SMTP server configuration (WireMailSMTP) Google App Passwords setup complexity Emails constantly landing in spam folders Delayed delivery (sometimes 5-10 minutes) No guarantee the recipient will see it quickly ๐Ÿ“ฑ SMS (Twilio, etc): Monthly fees just to keep a phone number active (~$1-15/month) Per-message charges (can add up quickly) US compliance requirements (verification, regulations) Not everyone wants to share their phone number ๐Ÿ’ฌ WhatsApp Business API: Requires business verification Complex setup process API fees and restrictions Limited to business accounts ๐Ÿ”” Push services (Pushover, etc): Requires purchasing apps ($5-10 per platform) Recipient needs to install and configure the app Additional barrier to entry Why Telegram? ๐Ÿ†“ Completely free - No monthly fees, no per-message charges, no app purchases ๐ŸŒ Widely available - Free to download on any platform, 900+ million users worldwide โšก Instant delivery - Messages arrive in 1-2 seconds, not minutes ๐ŸŽฏ Low barrier to entry - Just "install the free app and start a chat with the bot" vs "pay $5" or "give me your phone number" ๐Ÿ”’ Reliable - No spam filters, no deliverability issues, no carrier restrictions ๐Ÿ“ฑ Multi-platform - iOS, Android, Web, Desktop - works everywhere ๐ŸŽจ Rich features - HTML formatting, emojis, photos, documents, links Key Features ๐Ÿš€ Send text notifications with HTML/Markdown formatting ๐Ÿ“ธ Send photos and documents ๐Ÿ‘ฅ Support for multiple recipients (users and groups) ๐Ÿ”ง Simple admin interface with test button ๐Ÿ“Š Optional logging and debug mode โšก Optimized performance with configurable timeouts ๐ŸŽฏ Easy to integrate with hooks Real-World Use Cases E-commerce order notifications: $wire->addHookAfter('FormBuilderProcessor::processInputDone', function($event) { $form = $event->object; if($form->name === 'order-form') { $telewire = $this->modules->get('TeleWire'); $message = '๐Ÿ›’ <b>New Order</b>' . "\n\n"; $message .= '๐Ÿ‘ค Customer: ' . $form->get('customer_name')->value . "\n"; $message .= '๐Ÿ’ฐ Total: $' . $form->get('total')->value; $telewire->send($message); } }); Failed login attempts monitoring: $wire->addHookAfter('Session::loginFailed', function($event) { $telewire = $this->modules->get('TeleWire'); $name = $event->arguments(0); $message = 'โš ๏ธ <b>Failed Login Attempt</b>' . "\n\n"; $message .= 'Username: ' . $name . "\n"; $message .= 'IP: ' . $this->session->getIP(); $telewire->send($message); }); Content updates: $wire->addHookAfter('Pages::saved', function($event) { $page = $event->arguments(0); if($page->template == 'article' && !$page->isNew()) { $telewire = $this->modules->get('TeleWire'); $message = '๐Ÿ“ <b>Article Updated</b>' . "\n"; $message .= 'Title: ' . $page->title . "\n"; $message .= 'By: ' . $this->user->name; $telewire->send($message); } }); Send photos with captions: $telewire = $modules->get('TeleWire'); // Product photo when new product added $telewire->sendPhoto( $page->images->first()->httpUrl, "New product: {$page->title} - \${$page->price}" ); Send documents (invoices, reports): $telewire = $modules->get('TeleWire'); // Send generated PDF invoice $telewire->sendDocument( '/site/assets/invoices/invoice-123.pdf', 'Invoice #123 for Order #456' ); Installation Get a bot token from @BotFather on Telegram (takes 30 seconds) Install the module from GitHub Configure your bot token and chat IDs Click "Send Test Message" to verify everything works Requirements: PHP 8.2+ and ProcessWire 3.0.210+ Admin Interface Features The configuration page includes: โœ… Real-time connection status indicator ๐Ÿงช One-click test message button (AJAX, no page reload) โš™๏ธ Configurable parse mode (HTML/Markdown/MarkdownV2) ๐Ÿ“ Optional logging with debug mode for troubleshooting โฑ๏ธ Adjustable API timeouts ๐Ÿ”‡ Silent mode option (no notification sound) ๐Ÿ“Š Message length handling (auto-split long messages) Production Ready This module is currently running on several production sites: ๐Ÿซ E-commerce shop - order notifications, stock alerts ๐Ÿท Wine/liquor business - order confirmations, delivery updates ๐Ÿ“ฐ News portal - content publishing notifications Average response time: ~150-300ms per notification Getting Your Chat ID Find @userinfobot in Telegram Send any message - it will reply with your Chat ID Important: Start conversation with your bot by sending /start Enter the Chat ID in module configuration For groups: Add the bot to your group, make it admin, and use the negative Chat ID API Documentation // Get module instance $telewire = $modules->get('TeleWire'); // Simple text message $telewire->send('Hello from ProcessWire!'); // HTML formatted message $message = '<b>Bold</b> <i>italic</i> <code>code</code>'; $telewire->send($message); // Send with custom options $telewire->send('Silent notification', [ 'disable_notification' => true, 'parse_mode' => 'Markdown' ]); // Send photo $telewire->sendPhoto('/path/to/photo.jpg', 'Optional caption'); // Send document $telewire->sendDocument('/path/to/file.pdf', 'Document caption'); Feedback Welcome! I'd love to hear your thoughts, use cases, and suggestions. If you've been frustrated with email deliverability or SMS costs for notifications, give this a try! GitHub: https://github.com/mxmsmnv/TeleWire Thanks to the ProcessWire community for the inspiration and all the great modules that helped me learn the PW module system!
    12 points
  10. End of 2025 the relaunch of the Kubota Brabender Technology Website went live. KBT is a global leader in feeding technology and bulk solids handling. The technical production is developed by me, Olaf Gleba. The grafic design is supplied by C&G: Strategische Kommunikation GmbH. Homepage: https://www.kubota-bt.com The site uses a lot of asynchronous calls in several sections. 1. The product search is ajax driven and also preserve entered filter options while browsing the product pages (and all other pages) with session.storage. 2. Because there are many global partners and locations, it is neccessary to allow to narrow down the selection for proper contacts. 3. The page media holds all available downloads and media content. This includes magazines, videos, terms of contract and works standard specifications. The videos are implemented with help of the HTML Dialog Element. Work Standards documents are supplied/collected from one source (product page) to avoid duplication. 4. Backend: As most of the time, i provided content modules that fits the client needs. This and that: PrivacyWire (@joshua) as CCM (just a few cookies to handle Matomo and external movie content) Uses the SearchEngine Module (@teppo) to handle (multilanguage) site search Wire Mail Smtp (@horst)to deliver automated e-mails Heavy use of Fieldtype AssistedURL (Fork by @adrian) to provide language dependend, local file linking (fieldname_[de|en] approach) Distribution of concatenate/minified css and javascript is cachebusted (happens within my developement environment,- no modules (like AIOM etc.) involved). The site uses a bunch of modules provided by the ProFields Package (for example Repeater Matrix and Table Fieldtypes).
    11 points
  11. Hey, I've started to create a Media Hub for Processwire. [Edit...newest updates to UI are in later posts] Screenshots attached. Obviously a few UI improvements are needed ๐Ÿ™‚ One of my clients requested a centralised media manager. I thought it'd be fun to give it a go and learn some stuff. I know that with a self-built Module, it'll always be maintained, and I have an active interest in evolving it. Shout out to @markus-th who just announced he is doing similar with WireMedia.
    10 points
  12. Hi everyone! I've built AiWire โ€” a module that connects ProcessWire to AI providers (Anthropic, OpenAI, Google, xAI, OpenRouter). GitHub: https://github.com/mxmsmnv/AiWire What it does $ai = $modules->get('AiWire'); // Simple call echo $ai->chat('What is ProcessWire?'); // Generate multiple fields at once $ai->generate($page, [ ['field' => 'ai_overview', 'prompt' => "Write overview..."], ['field' => 'ai_seo_meta', 'prompt' => "Generate meta..."], ], ['cache' => 'W']); // Auto-fallback if provider fails $result = $ai->askWithFallback('Translate this...', [ 'provider' => 'anthropic', 'fallbackProviders' => ['openai', 'google'], ]); Main features Multiple API keys per provider with auto-failover Connection testing from admin Interactive Test Chat with parameter controls File cache with TTL (day/week/month/year) Save AI responses to page fields Multi-turn conversations Full docs with 25 real-world examples Requirements PHP 8.1+, ProcessWire 3.0.210+, cURL, and at least one API key. If you try it out, I'd love to hear your feedback โ€” whether the API makes sense, if the docs are clear, or if you run into any issues. Thanks! ๐Ÿ™
    10 points
  13. Generates a .phpstorm.meta.php file for ProcessWire autocompletion in PhpStorm. Features Autocomplete wire container keys for wire('...') and Wire::wire('...') Autocomplete module names for Modules::get() and Modules::install() Autocomplete field names for Fields::get() Autocomplete template names for Templates::get() Autocomplete unique page names for Pages::get() Autocomplete hookable methods for Wire::addHook*() Autocomplete page status constants/strings for Page::status(), addStatus(), removeStatus(), hasStatus() Autocomplete field flags for Field::addFlag(), removeFlag(), hasFlag() Autocomplete template cache-expire constants for Template::cacheExpire() Autocomplete Inputfield collapsed constants for Inputfield::collapsed() Autocomplete sort flags for WireArray::sort()/sortFlags()/unique() and PageArray::sort()/sortFlags()/unique() Optional: Field type autocompletion per Page class (when enabled in module config) Usage Default path: site/assets/.phpstorm.meta.php (configurable in module settings). The file regenerates automatically when fields, templates, or modules change (debounced). You can manually regenerate from the module settings screen. Optional: enable "Generate page-class field metadata" in module settings for field type hints per Page class. This is intentionally basic. For richer field stubs, use AutoTemplateStubs. Examples Modules $tracy = $modules->get('TracyDebugger'); // Autocomplete + correct class type for navigation and code insight Wire Container $page = wire('page'); $pages = $this->wire('pages'); $cache = wire('cache'); // Autocomplete for keys like page/pages/cache/etc. Fields $body = $fields->get('body'); // Autocomplete field names, fewer typos Templates $tpl = $templates->get('basic-page'); // Autocomplete template names Pages $home = $pages->get('/'); // Maps to the page class when page classes are enabled Page Status $page->status(Page::statusHidden); $page->addStatus('draft'); $page->removeStatus(Page::statusUnpublished); $page->hasStatus('locked'); Field Flags $field->addFlag(Field::flagAutojoin); $field->removeFlag(Field::flagAccess); $field->hasFlag(Field::flagGlobal); Template Cache Expire $template->cacheExpire(Template::cacheExpireParents); Inputfield Collapsed $inputfield->collapsed(Inputfield::collapsedYesAjax); Sort Flags $items->sort('title', SORT_NATURAL | SORT_FLAG_CASE); $items->sortFlags(SORT_NATURAL); $items->unique(SORT_STRING); Page-Class Field Metadata (Optional) $home = $pages->get('/'); // $home is HomePage (page class) // Field types are inferred from the template fieldgroup // e.g. $home->hero_image -> Pageimage or Pageimages depending on field settings Hooks $wire->addHookAfter('Pages::save', function($event) { // Autocomplete hookable methods while typing the hook string }); Notes Hook scanning reads ProcessWire core, modules, and admin templates to build the hook list. If page classes are enabled, page names map to their page class; otherwise they map to Page. Improvement suggestions and PRs are welcome. https://github.com/phlppschrr/ProcessWirePhpStormMeta
    9 points
  14. Hi everyone, Iโ€™m currently working on a module called WireMedia Library and wanted to share the current state of development to get some feedback on the concept. The main goal is to provide a central interface for managing media across the entire ProcessWire instance while staying 100% compatible with the native storage system. The Concept: The module acts as a central hub. You can upload files to the library and then select them from any page. When a file is selected, it is copied into the local pageโ€™s file/image field. This ensures that the files remain "native" to the page they are used on, keeping your API calls and templates exactly as they are. Key Features of the current prototype: Central Media Overview: A unified view of all media assets in the system. Usage Tracking: The module indexes where files are used. Even if a file is used within a Repeater, it identifies the "leading" parent page so you know exactly where your assets live. Database Indexing: A custom database table keeps track of file locations for fast performance. Rebuild Index: A tool to rescan the system and ensure the database stays in sync with the file system. Native Workflow: Since files are copied to local fields, you can still use all native PW features (like cropping or focus points) directly on the target page. Planned: Permission System: Granular access control for different user roles/folders. I am still undecided about the final licensing or if/how I will release the module, but I wanted to show the UI and the logic behind it to see if this approach resonates with the community. Iโ€™d love to hear your thoughts on the "copy-to-field" approach and the general UI!
    9 points
  15. Good day, @bernhard! First of all, I have to thank you for being who you are. A lone talented enthusiast trying to build a sustainable living on top of our beloved CMS. But not just making sites like the rest of us. But creating your little module-selling empire))) Taking on every hard problem ever put in front of a PW developer and solving it in no time. You have leaded the way for us for some many years. Everyone here has been following you in one way or another. And thus I feel sad about you taking this decision. Yet in the same time I can imagine the freedom you should feel after it. I really wish you good luck in any place your future journey will take you! I sounds like I am saying goodbye to someone leaving, but I am not. I am just saying that every end is the new beginning. What else I would love to invite you into doing is to analyze why this path of yours (creating a bunch of super cool module) didn't lead you to the place expected. Recently @kongondo, the only other prominent paid module creator I can remember, has done the same exit as you. Why is this? This question is of interest to me because I have many times thought about how I myself could build my income upon what I love and know - ProcessWire. Could it be, that PW is so much a DIY kind of thing, that most of us want to build something of our own and are not ready to subdue to modules authors' way of doing things (other than @ryan himself)? Or does everyone here enjoys opensource so much that proprietary is something to avoid? Or is it just simply not enough of target audience?
    9 points
  16. Awesome article that sums it all up neatly. Thanks for this comprehensive guide, Ryan! I converted the content of this article into a reusable AI agent skill. Available here: https://github.com/gebeer/processwire-ai-docs/tree/main/skills/pw-page-classes
    8 points
  17. Thx for your support! Hope the modules will be useful for you. It's public now, thx for letting me know! ๐Ÿ™‚ I have released my first open source PW module 9+ years ago and I have realised that nothing of what you mentioned pays my bills ๐Ÿ˜‰ And all you mentioned is equally true for paid modules - the difference being that making money allows you to dedicate more time and thus provide even better solutions/docs/support. Or tackle problems that would otherwise not be possible to tackle. I think PW and all of us would benefit a lot more if we had a working ecosystem for paid modules and a larger market to sell the modules to. I just don't see that happen and that's why I had to give up and find another way. So I have a bit of a problem calling it "inspiring". I hope it is not and others find a better way. Open sourcing my modules was really just about minimising damage (for myself and my clients). If others benefit from that decision, that's great - but it was not the reason and I would not recommend anybody to take this as inspiration. ๐Ÿ™‚ Thank you ๐Ÿ™‚ Hey @Ivan Gretsky thank you very much. I think your post is spot on and you are asking some very good questions. Some very important questions. The problem that I have is that I think that those questions are not only important to you but would also be important for the PW project. I'm not sure who you are asking for? If you are asking for PW and try to push it forward, I'm sorry, I can't answer that here in a public thread unless I'm asked from an official source and get the feeling that the people in charge are interested. I hope you understand, but I don't want to burn my energy ๐Ÿ™‚ If you are asking for yourself, though, I'm happy to share anything I have learned, observed, experienced in a personal chat with you. Just drop me a line and we can meet and talk about it. Would be nice to meet you after such a long time!
    8 points
  18. Thank you for sharing your invaluable work and contributions @bernhard! You had a lot of options with how to move forward and I believe that open sourcing your modules ensures that your work carries on into the future and continues to benefit both ProcessWire developers and users alike. I do want to share some thoughts and contribute to what @bernhard said about "feature complete". Most of the modules you have built are indeed robust and offer a large number of features that are implemented well and will continue to bring value long into the future. Modules like RockPageBuilder offer a solid set of features and are built in a very extensible and customizable way that puts a lot of power in the hands of developers. If any are reading this and are just finding out about it or have not yet had a reason to use it yet, I highly recommend taking a look! Other modules like RockMigrations have become staples in my workflow and will continue to be. Whether new features are added or not, the utility and quality of these contributions stand on their own. I also want to share some thoughts with the greater community. ProcessWire is a powerful tool that is developer-focused and easy to use for beginners while being powerful enough for advanced applications and more senior developers. It's one of the reasons we all love working with this platform. It also means that this community is comprised of people of many levels of skill and creative abilities. These are the factors that make open source software work. Whether you're working with the core or a module from any developer that is open source, your contributions matter and they are a way to "pay it forward" and give back to the community that makes your work possible. The vast majority of modules are free to download and use, and that "free" to you comes at a cost to module and core developers in both programming and support time. These are hours spent beyond our professional life. Nights and weekends, and breaks from our jobs to respond when something is urgent. Keep the developers in mind and remember that burnout is a real thing in the open source community. Greater involvement and contribution helps that greatly and also helps the developers you rely on for quality code you use stay engaged and make offering their work to the community enjoyable. Many hands make for light work. If you're using a module and run across an item that can be improved, a bug that hasn't been reported yet, or have an idea for a new feature then please consider forking, contributing, and pushing upstream via PRs on Github. If you are able to see something, take a moment to try and find a solution- I guarantee it will always be greatly appreciated and your efforts will not go unnoticed. You'll find some of mine coming to @bernhard modules in coming weeks. If you haven't contributed to open source before or find the process intimidating, please consider a module contribution for your first time out. The thoughtfulness and helpful attitudes here in the forums continue on module Github repositories. Those repository owners and module maintainers are the same people who are members of one of the greatest developer communities around. Never forked a repository or opened a PR before? Anyone with experience here is ready to help. You'll level up your skills, increase your confidence, and the satisfaction you'll feel cannot be overstated. These can be as simple as small changes to make a code base compatible with a new version of PHP, or a little tweak to some JS! I wanted to take a moment to mention this here because the release of these modules, much like those that were open-sourced by @kongondo and others, have a future through contribution. I don't mean to hijack your thread @bernhard but I think what you have shared offers a great opportunity to communicate these ideas in appreciation and encouragement to others. Thank you again @bernhard for the wealth of knowledge you openly share here and the guidance that you have offered to others. It is inspiring and, on a personal note, has immeasurably advanced my knowledge and confidence as a ProcessWire developer. @Jim Bailie The concept of a paid platform for modules has been discussed by many both in public and private. I don't know that there's a single answer to that question. Hopefully that may come about one day, it would mean a lot to the sustainability of ProcessWire. When it comes to taking a shop from concept to reality from a community standpoint it always comes down to "if not me, then who?". Should Ryan take time from the core to build it? Maybe it would be better for a team to collaborate and offer help to create an official channel. I think what I mentioned above underscores the importance of not relying on one person to solve the problem. I'm sure Craft had a team of people working together to make their shop come to life and also requires work to keep it going. If one person did all of it for Craft I would be truly shocked. Hey- RockCommerce is open source... maybe it's a starting point ๐Ÿ˜Ž
    7 points
  19. Hi everyone! ๐Ÿ‘‹ I'd like to share SquareImages - a simple module that creates perfect square images from any source format. Born from a real-world need: displaying vertical product images (like Coca-Cola bottles) uniformly in galleries and grids without distortion or awkward sizing. The Problem // Traditional methods don't work well for mixed aspect ratios: $image->width(300); // Too narrow for vertical images $image->height(300); // Too wide $image->size(300, 300); // Distorted The Solution // One simple method - smart cropping, perfect squares: $square = $image->square(300); Key Features ๐ŸŽฏ Smart Cropping - Automatically centers on longer dimension ๐Ÿ“ฆ Format Preservation - Maintains original format (JPG/PNG/GIF) ๐ŸŒ WebP Support - Chain with ->webp() for compression โšก Performance - Fast URL generation ๐Ÿ’พ Automatic Caching - Built on PW's image engine Quick Example <div class="product-grid"> <?php foreach ($page->products as $product): ?> <?php $thumb = $product->photo->square(300); ?> <img src="<?= $thumb->url ?>" alt="<?= $product->title ?>"> <?php endforeach; ?> </div> Perfect uniform squares, regardless of source dimensions! API Methods $image->square(400); // Main method $image->squareWidth(500); // Based on width $image->squareHeight(600); // Based on height $image->getSquareURL(300); // Direct URL (faster) // WebP conversion $image->square(500)->webp(); // 25-65% smaller files Installation GitHub: https://github.com/mxmsmnv/SquareImages cd site/modules/ git clone https://github.com/mxmsmnv/SquareImages.git Or download ZIP and extract to /site/modules/SquareImages/ Then refresh modules in admin and install. Use Cases E-commerce product galleries Team member avatars Blog thumbnails Social media previews Instagram-style grids
    7 points
  20. Agree that the site is too developer-centric at the moment. And while people might correctly say this is the target audience, none of my clients using ProcessWire are technical. They are marketing managers, business owners, copywriters, CEOs, eLearning folks etc. They don't care about the API, what a CMF means, what hooks are, or what Modules are. They want a nice, stable UI and editing experience, and to know that if they need custom stuff, it can be done. So my point is, the current Processwire homepage does an OK job of mentioning some of the features these personas might like (the tree, the simple editing etc). However, the site is largely developer-centric, and I believe the appeal can be broadened with: 1: A comprehensive ProcessWire for... section This would be a top-level nav item with dedicated pages for Marketing executives and assistants Content writers/copywriters SEO specialists social media/comms etc etc and thats just the tip of the iceberg, but we should approach it with three key non-developer personas in mind: Publishers (write/edit content) Maintainers (keep info accurate) Promoters (campaigns, SEO, sales, social) And I realise there will be a lot of overlap between the sections, but that's fine. 2: Video walkthrough The website badly needs a UI walkthrough. ProcessWire in 60 seconds... type thing. Made for non-technical people...a quick look around the UI and I honestly think that's 90% of the work done. I realise video work can be a time sponge so I'd focus on item 1 first. I'm happy to help out on item 1 if @ryan needs help there.
    6 points
  21. @olafgleba @maximus I just pushed an update to kickstart.php. It is now possible to install any arbitrary Site Profile! You can either provide a URL to a ZIP file or upload a local ZIP file directly within the tool. The script extracts the profile to the correct location, allowing the standard ProcessWire installer to pick it up seamlessly. Give it a try and let me know if it works for your custom skeletons.
    6 points
  22. I second this wholeheartedly. The community is among the very best out there, and the lack of opinion, the clear structure and the ease of extending make PW a wonderful tool. It's a sad fact that my days of working with ProcessWire are mostly over. My job responsibilities have changed over time, and the demand for wholly integrated cloud systems led my employer to migrate our intranet site with tens of thousands of pages and a lot of advanced functionality to another platform (let's not talk about the manpower needed to do that and the gaps left). There are of course advantages, but I can say that we had a tailored-to-fit solution on a level you don't find often, from ordering breakfast or lunch from local suppliers, over advanced forms connected to HR systems and Active Directory data, providing specialized integrated databases and automated workflows to our departments, to driving technical sales with dynamically generated interlinked views on bills of material, stocks and data sheets pulled directly from SAP. A piece of software more than 60% of 1300 worldwide employees used daily and that ran with 100.0% availability on a single IIS server with only a bit of memcache magic to keep things speedy. Over more than ten years, periodic updates went through with nary a hitch. My heart bleeds a bit. Not working with PW every week also means that I'm not actively using the modules I built anymore. I'll have to go over my little babies one by one, retire those that have been surpassed by better approaches by now and find new pet owners for the others.
    5 points
  23. It's a bit over a year since I started this post and it's crazy how far AI and cursor got! Huge shoutout to @gebeer who is my main source of wisdom when it comes to AI related stuff ๐Ÿ™‚ I wanted to share a video that I watched recently. It is quite lengthy, but I was looking for exactly that to make sure I don't miss any basics. For me it was eye opening, so I wanted to share it: My personal takeaways/learnings: I have thought for a long time that AI is great to read/understand/explain or help me find something in my codebase but for actual coding it's not very helpful most of the time (other than cursor tab, which is awesome!) You can run multiple agents in cursor at once, and you can run multiple models at once, which is crazy The better you setup your environment, the better the results (obviously...) AI can write all your RockPageBuilder blocks with RockMigrations code easily You can actually TALK to cursor in the chat, which is a lot quicker than typing. You can even TALK to it in german and it will translate it to english on the fly, which is crazy. This is just the beginning So the question for me was is it really worth the effort of setting up your environment so that AI does the work for you and then in the end you spend more time debugging than if you just went ahead and coded it from scratch? I'm not sure yet, and I asked that question today @gebeer. He said clearly yes, and my gut said I can imagine he is right, but I did not really experience it myself. Today that changed. I took some time to try a new workflow for a client request. Usually I would have added code by hand, as that's a lot quicker. Why? Because you either start prompting and get bad results or you have to invest a lot of time upfront. But I know how it feels to invest some time upfront and then have superpowers forever ๐Ÿ™‚ So I gave it a try and after a quick emergency rescue session with @gebeer I got very good results in actually very little time. And once I started to adopt that workflow it started to make sense more and more and I started to answer the question to myself: Is the effort worth it? Clear answer: YES So I want to encourage everyone to watch the video, try it out, ask for help if you hit any roadblocks. So why do I think it's worth it? Simple example: I asked AI to implement a new RockPageBuilder block. It did the backend for me quickly and easily. Then it did the frontend for me. The frontend needed more time and debugging, but I then added the uikit docs to my project and told cursor to add the docs to my cursor rules/skills/whatever (still confused, but cursor knows what to do). Then results seemed to get even better and it even fixed an issue in a way that I would have never thought of (because I didn't know this option was there). So I even learned something new. Finally I saw an issue in my .latte file, which is quite a common mistake: AI forgot to add |noescape to the {$page->headline} output, which made the headline "Foo & Bar" show up as "Foo &amp; Bar". I guess every latte user knows that problem ๐Ÿ™‚ The solution: Tell AI to fix the issue and to also add that info to the frontend-dev skill/rules. That means it will likely never make this mistake again! This is a really powerful approach. I'm quite impressed. And I think I'll need a more expensive subscription soon ^^ Which is one of the downsides. You have been warned! ๐Ÿ˜„๐Ÿ˜‰ PS: The initial setup is also quite easy. All I did is to talk to cursor: A bit messy instructions and lots of mistakes, but it doesn't matter as long as cursor understands you. I'm quite sure the results are not perfect, but from what I read in the instructions for the AI it's a quite good overview of the project! And it's something to build upon and grow ๐Ÿ™‚
    5 points
  24. @bernhard I want to express my gratitude for all you have contributed to the PW community over the years. And I commend you on your decision to open source your modules. Many of your modules have become part of my workflows for most projects over the years. I was happily paying for the bundle. It was definitely worth it. I hope that the community will pick up on your move and contribute through PRs for further refinement and new features where needed. Thank you again, Bernhard. You and your work are both much appreciated :-)
    5 points
  25. In line with this topic, I recently expanded AutoTemplateStubs to include ProFields Stubs. There should be stubs for FieldtypeTable, FieldtypeTextareas, FieldtypeCustom and RepeaterMatrix (including stubs for all types). I haven't created a PR yet because I wanted to test it myself first, but since it fits so well with the blog post, if anyone would like to help with testing: https://github.com/phlppschrr/AutoTemplateStubs
    5 points
  26. Hey @ryan, hey all readres, I'd like to propose two features that would help those of us working with business and organizational clients. OAuth 2.0 Login Support Several of our clients use Microsoft 365, and it would be nice to integrate their websites seamlessly with e.g. Microsoft Entra ID. Native OAuth 2.0 support would allow users to log in with their organizational accounts instead of managing separate credentials. For an urgent case I'll try to set up @flydev's module (https://processwire.com/modules/oauth2-login/) but unfortunately the creation of users is not yet (?) possible. Microsoft Graph API for Email Delivery As said before, more and more peopele rely on Microsoft 365, and traditional SMTP with basic authentication is being phased out. Supporting Microsoft Graph API would allow us to: Use OAuth 2.0 tokens instead of storing SMTP passwords Leverage existing Microsoft 365 infrastructure Ensure better deliverability and avoid authentication headaches Native support for both would make ProcessWire from my perspectibe a more compelling choice for organizations looking for enterprise-grade SSO and email solutions.
    5 points
  27. Warning, this module is "vibe coded" and still lightly tested by me, but planning on launching it into production soon. Please test with caution. Think it should be something pretty useful? Sometimes I have options that would be better shown as images/labels, this sets a new Fieldtype that can be used with to new Inputfields that render either checkboxes or radio but tons. https://github.com/elabx/FieldtypeImageLabelOptions You should be able to change the type of any FiletypeOptions to this field and its data should stay consistent. Also inspired by @kixe's FieldtypeSelectColorOptions
    5 points
  28. Seems this module has not had its own forum thread. Now it has. https://github.com/baumrock/RockIcons
    5 points
  29. Published Version 2.4 with support for custom user role permissions: promptai allows to use the prompts in page edit promptai-config allows to add/edit new prompts
    4 points
  30. I wanted a way to chat with my Processwire site and built a Module (PW MCP) and an MCP server to connect into it. It's a private repo at the moment but it can be public if anyone finds it useful. It's basically a way to use the Cursor Chat Ui to query my site, fields, templates and content. Here's part of the readme which explains it better. What Is It? ProcessWire MCP is a bridge between ProcessWire and Cursor IDE (the AI-powered code editor). It lets you query your ProcessWire site's structure and content directly from Cursor's chat interface using natural language. Instead of writing selectors or browsing the admin, you can just ask: "What templates does this site have?" "Show me the fields on the blog-post template" "Search for pages containing 'summer'" "Find all images with 'lake' in the filename" Why I Built It Cursor can see your template files and code in the local directory, but it can't see what's actually in your ProcessWire database โ€” which templates and fields are registered, what pages exist, or what content they contain. With ProcessWire MCP, the AI can: Query the actual database schema (not just parse template files) Look up page content by ID, path, or selector Understand field configurations (types, settings, which templates use them) Search across all text content and find files/images Get RepeaterMatrix content with type labels See file metadata (dimensions, descriptions, URLs) It's the difference between seeing $page->body in code vs. knowing what that page's body actually contains. Architecture Cursor Chat โ†’ MCP Server (Node.js) โ†’ PHP CLI โ†’ ProcessWire API The module consists of: PwMcp โ€” A ProcessWire module with a CLI interface mcp-server โ€” A Node.js server that speaks the Model Context Protocol The CLI can also be used standalone for quick queries from terminal. Available Commands Command Description health Check connection and get site info list-templates List all templates with field counts get-template [name] Get template details and fields list-fields List all fields with types get-field [name] Get field details and usage get-page [id\|path] Get page by ID or path with all field values query-pages [selector] Query pages using PW selectors search [query] Search content across all text fields search-files [query] Search files by name/extension export-schema Export complete site schema Example: Health Check php site/modules/PwMcp/bin/pw-mcp.php health --pretty { "status": "ok", "pwVersion": "3.0.241", "siteName": "www.example.com", "moduleLoaded": true, "counts": { "templates": 45, "fields": 72, "pages": 960 } } Example: Content Search Ask Cursor: "Search for pages containing 'summer'" { "query": "summer", "count": 5, "results": [ { "id": 1764, "title": "Lake District walks in summer", "path": "/guides/lake-district-summer/", "template": "page-guide", "matchedField": "Body", "snippet": "The Lake District offers some of the best walking trails in summer. From gentle lakeside strolls to challenging fell walks..." } ] } Example: File Search Ask Cursor: "Find images with 'lake' in the filename" { "query": "lake", "count": 5, "results": [ { "filename": "lake-windermere-sunset.jpg", "url": "/site/assets/files/1070/lake-windermere-sunset.jpg", "size": 31207, "sizeStr": "30.5 kB", "description": "Sunset over Lake Windermere", "field": "Images", "page": { "id": 1070, "title": "Lake District walks in summer", "path": "/guides/lake-district-summer/" }, "width": 500, "height": 626 } ] } Example: Get Page with All Fields Ask Cursor: "Get the page at /about/" { "id": 1050, "name": "about", "path": "/about/", "url": "/about/", "template": "basic-page", "status": 1, "statusName": "published", "parent": { "id": 1, "path": "/", "title": "Home" }, "numChildren": 5, "created": "2023-05-15T10:30:00+00:00", "modified": "2024-11-20T14:22:00+00:00", "fields": { "title": "About Us", "body": "<p>We are a team of dedicated professionals...</p>", "Images": { "_count": 2, "_files": ["team-photo.jpg", "office.jpg"] } } } Example: RepeaterMatrix Support The module fully supports RepeaterMatrix fields, returning the actual content with type labels: { "matrix": { "_count": 3, "_items": [ { "_typeId": 1, "_typeLabel": "Body", "Body": "<h2>Welcome to our guide</h2><p>This guide covers...</p>", "Images": null }, { "_typeId": 2, "_typeLabel": "FAQs", "faq_question": "What is the best time to visit?", "faq_answer": "The summer months offer the best weather for walking..." }, { "_typeId": 3, "_typeLabel": "Call to Action", "cta_title": "Plan Your Visit", "cta_link": "/contact/" } ] } } So thats the first part done and working. My next plan is to be able to 1. PULL / convert a databse page into a local text file which lists all page properties, fields, template etc 2. edit the file as a local text file 3 PUSH the text file back into PW so that the original content picks up the changes Just having fun and building something useful. Very likely there are similar solutions or better ways to handle this but this suits my workflow ATM. Cheers P
    4 points
  31. Some more work. Not sure why the images are so fuzzy Image detail page You can edit the usual stuff...Title, Alt, Description, and add Tags etc Some utilities in there too such as Download, Copy URl, Duplicate, Delete If an image has Crop versions they are displayed under the main image Crop versions has thumbs and table view A crop version has a detailed view too Image Crop page There are presets, but you can create your own named crops Save as a crop version or save as a new image. The hardest part is in progress which is A custom Inputfield which allows you to add images from the MediaHub. All while maintaining a connection back to the hub source file. IE it's important that there's no duplication and that the images in the Media Hub are a true source / canonical version Displaying images in the page edit field in a nice consistent way with the existing UI. As much as possible, I want the user to feel like this the core and not some bolt-on with its own CSS. Although I am changing some thingsโ€ฆ Hope you like! P
    4 points
  32. Hey everyone, I have some updates to MediaHub to share. Media Hub view Screenshot of the Grid view... This is the grid view showing a thumbnail of all your images. Each card has helpful meta data (PNG, file size etc) Some images have crop applied denoted by the small pink badge. IE Lisbon tiles has 4 crop versions. Usual filters at the top and a search bar. Screenshot of the Table view. Handy if you have hundreds of images Displays tags too Screenshot of the Upload / Drag and drop mode There's some nice aniamtion / UI when the system is uploading several images Tomorrow I'll share more...
    4 points
  33. Hi everyone, As promised, the Beta version of WireBooking is now available on GitHub! You can find the repository here: https://github.com/markusthomas/WireBooking I would love to get your feedback on the installation process and general usability. If you find any bugs or have suggestions for improvements, please open an issue on GitHub. Happy testing!
    4 points
  34. These are very good questions. My honest take: PW is still very much a niche product. People who've been working with it for years learned to appreciate it. But it's very hard to convince anyone to jump in and dive deep until you discover the many advantages PW offers. And yeah, most devs have their specific workflows and it is just inconvenient to adapt new ones that might actually work better. Time/energy constraints may contribute to that. I can only say for me personally, I'd always buy and support proprietary modules developed by experienced PW devs although I am a FOSS enthusiast.
    4 points
  35. I understand what you mean about the frustration with the documentation, and that to access support you have to pay for a year. But I see it as my way of giving back for the work Ryan does, and I always renew my Pro modules support, even if I donโ€™t really need it. All the work, maintaining the CMS, forum administration, support, etc.has to generate income, otherwise ProcessWire wouldnโ€™t exist. And honestly, every day Iโ€™m grateful to have the option to avoid working with WordPress and sleep peacefully at night, knowing my sites wonโ€™t get hacked because of some module that hasnโ€™t been updated. Also, English isnโ€™t my native language, and I had an AI review this text.
    4 points
  36. You would need to use an SQL query to first get the IDs of matching pages, then use those IDs in a PW selector. MySQL has a DAYOFWEEK() function but it starts the numbering on Sunday which is easy to forget. So probably better to use the DAYNAME() function instead. // Get the IDs of all pages where the day name of the date value is Monday $fieldName = 'event_date'; // The name of your date field $tableName = "field_$fieldName"; // The table name is the field name prefixed with "field_" $weekday = 'Monday'; // The day of the week you want to match $stmt = $database->prepare("SELECT pages_id from $tableName WHERE DAYNAME(data) = :weekday"); $stmt->bindValue(':weekday', $weekday); $stmt->execute(); $ids = $stmt->fetchAll(\PDO::FETCH_COLUMN); $idsStr = implode('|', $ids); // Find PW pages $items = $pages->find("template=event, id=$idsStr");
    4 points
  37. A wrapper around Markup Cloudflare Turnstile for ease of use in FormBuilder.
    4 points
  38. Thank you @bernhard for sharing your modules and for your open source contribution to the ProcessWire community! When I was developing modules, I initially thought of each one as a potential source of income. But over time I realized that the real value lies in something greater than money โ€” the support from users, their questions, the connections made, and the ability to contribute to this amazing community. That's what makes it truly worthwhile. Your decision to open source your modules is inspiring and will benefit many developers. Wishing you all the best! ๐Ÿ™
    4 points
  39. I spent a few hours this morning making an MCP module for ProcessWire similar to Laravel Boost. I'm going to call it Octopus. In just 2-3 hours with Opus 4.5, I'm already what feels like being done with 90% of it. I'm going to finish the remaining 90% (heh) as I work on various projects to actually test it. I will have to figure out the best way on how to provide ProcessWire documentation to the MCP (hence why I'm on this thread), but even without it, Opus 4.5 is insanely good in following ProcessWire conventions, even with little context! The hype is real. Let me know if you have any questions or suggestions. Screenshot attached.
    4 points
  40. Donโ€™t forget Cursor cloud agents. Give a cloud agent a plan and the agent works in the background while youโ€™re away from the laptop. I give them a task on the iPad when Iโ€™m at the gym and by the time Iโ€™m home thereโ€™s a new branch waiting for me. I canโ€™t verify this but somehow Iโ€™ve often found the quality of the cloud agents to be better than the desktop ones even on the same model. Canโ€™t be true? But feels that way.
    3 points
  41. https://github.com/phlppschrr/processwire-knowledge-base
    3 points
  42. @gebeer I have started developing a โ€˜processwire-knowledge-baseโ€™ skill. To do this, I converted all blog articles and tutorials from the website as well as the API docs into Markdown. However, I haven't tested the skill yet. I think it still needs some fine-tuning. It's still a private repo at the moment, but if you're interested in taking a look, I'm happy to make it public.
    3 points
  43. @bernhard thanks for sharing the video. And exciting journey you had there :-) Eventually this is where things are going, I guess. Would be great to know who in this community is working on similar stuff. I'm currently creating a collection of skills that can be plugged-in to PW projects here: https://github.com/gebeer/processwire-ai-docs Would love to collaborate with others on that and exchange ideas.
    3 points
  44. I think that sums it up ๐Ÿ™‚
    3 points
  45. @Ivan Gretsky I'm always a little reluctant to make a blanket statement like "avoid markup in page classes", but I'm referring to what I think works best with the projects I work on. The files in /site/templates/ are the view layer, as nearly all code in there is aimed at generating markup/output. Even if something isn't directly generating markup, it's still finding and preparing things for output. Most markup comes from "partials", which are files that I put in /site/templates/parts/, or if exclusive to a particular template, then /site/templates/[template]/. And then I either include() them, or files()->render() them from the site's template files. I primarily use Markup Regions. The _main.php establishes the base markup: <?php namespace ProcessWire; /** @var Page $page **/ ?><!DOCTYPE html> <html> <head id="html-head"> <?php include('./parts/html-head.php');?> </head> <body id="html-body"> <header id="header"> <?php include('./parts/header.php');?> </header> <h1 id="headline"><?=$page->title?></h1> <main id="content"> <?=$page->body?> </main> <aside id="sidebar" pw-optional> </aside> <footer id="footer"> <?php include('./parts/footer.php');?> </footer> </body> </html> Below is a template file for the /products/ page which lists product pages, supports pagination, and uses URL segments for sorting: <?php namespace ProcessWire; // products.php /** @var ProductsPage|CategoryPage $page */ $products = findProducts($page); $body = input()->pageNum === 1 ? $page->body : ''; $headline = $page->get('headline|title'); ?> <h1 id="headline"><?=$headline?></h1> <main id="content"> <?=$body?> <?php include('./parts/sorts.php'); // no expects ?> <?php include('./parts/products-list.php'); // expects $products ?> </main> <aside id="sidebar"> <?php include('./parts/categories-list.php'); // no expects ?> </aside> The category template file works exactly the same way, except that it lists products for the category rather than listing all products. The same code works either way, so "category.php" just includes "products.php": <?php namespace ProcessWire; // category.php include('./products.php'); There's that findProducts() function above in the products.php template file -- I usually have helper functions in a /site/templates/_func.php, /site/templates/_products.php, or /site/templates/products/func.php (assuming exclusive for "products"). Another place would be for the ProductsPage and CategoryPage to have findProducts() methods, but usually I don't want the page classes getting involved with detecting stuff about the current request (sort, pageNum, etc.) so like these in a simple function library file: <?php namespace ProcessWire; // file site/templates/_func.php included by _init.php function getSorts(): array { return [ 'name' => 'A-Z', '-name' => 'Z-A', 'price' => 'Price (low-high)', '-price' => 'Price (high-low)', 'created' => 'Date added (oldest)', '-created' => 'Date added (newest)' ]; } function getSort(): string { $sorts = getSorts(); $sort = input()->urlSegment('sort-(*)'); if(empty($sort)) $sort = 'name'; if(!isset($sorts[$sort])) wire404('Invalid sort'); return $sort; } function findProducts($page, $limit = 20): PageArray { $sort = getSort(); $find = "template=product, sort=$sort, limit=$limit"; if($page instanceof CategoryPage) $find .= ", categories=$page"; return pages()->find($find); } Here's an example of a ./parts/products-list.php file: <?php namespace ProcessWire; // file: parts/products-list.php /** @var PageArray|ProductPage[] $products */ $subhead = $products->getPaginationStr('Products'); $pagination = files()->render('parts/pagination.php', [ 'items' => $products ]); ?> <h3><?=$subhead?></h3> <?=$pagination?> <ul class="products-list"> <?php foreach($products as $product): ? <?php include('./parts/products-item.php'); // expects $product ?> <?php endforeach; ?> </ul> And the parts/products-item.php, though in reality there would likely be more to it: <?php namespace ProcessWire; // file: parts/products-item.php /** @var ProductPage $product */ ?> <li class="products-item"> <h3><?=$product->title?></h3> <p><?=$product->summary?></p> <p><a href="<?=$product->url?>">View Details</a></p> </li> To complete it, here's the parts/sorts.php file: <?php namespace ProcessWire; // file: parts/sorts.php $currentSort = getSort(); $url = page()->url; $sorts = []; foreach(getSorts() as $sort => $label) { if($sort != $currentSort) $label = "<a href='{$url}sort-$sort/'>$label</a>"; $sorts[] = $label; } echo "<p class='sorts'>Sort by: " . implode(' / ', $sorts) . "</p>"; If I start needing to output products in more places in the site, then I'll usually do fewer include()'s and move the rendering to dedicated functions. That way these things render in their own variable namespace and don't bleed variables or overwrite variables in the main rendering. So this would also go in that _func.php (or _products.php or ./products/func.php) mentioned above, and the include() calls in template fiels would be replaced with render...() calls: function renderProducts(PageArray $products): string { return files()->render('parts/products-list.php', [ 'products' => $products ]); } function renderCategories(): string { return files()->render('parts/categories-list.php'); } function renderPagination(PageArray $items) { return files()->render('parts/pagination.php', [ 'items' => $items ]); } So if using render() functions then the <main> with the include('./parts/products-list.php'); would get replaced with this: <main id="content"> <?=$body?> <?=renderProducts($products)?> </main> Ah yes, I hadn't thought about that in a long time. I can't remember if that was implemented yet or not. I'll find out. If not yet implemented I'll have to implement it, it should be fairly simple.
    3 points
  46. Maybe take a crack at building a form module. Probably save some time. You might want to consider using features Tailwind makes available to style with utility classes outside of markup. This is the most efficient way to apply consistent styling to markup you aren't generating or don't control. This is for v3 but there are options in v4 to do the same. @layer base { label { @apply mb-1.5; } input[type="text"], input[type="email"], input[type="url"], input[type="password"], input[type="number"], input[type="date"], input[type="datetime-local"], input[type="month"], input[type="search"], input[type="tel"], input[type="time"], input[type="week"], [multiple], textarea, select { @apply border-neutral-400; } button, [type='text'], [type='email'], [type='url'], [type='password'], [type='number'], [type='date'], [type='datetime-local'], [type='month'], [type='search'], [type='tel'], [type='time'], [type='week'], textarea, select, select[multiple], [type='checkbox'], [type='radio'] { @apply focus-visible:ring-2; @apply focus-visible:outline-none; @apply focus-visible:ring-cerulean-600; @apply focus-visible:ring-offset-2; @apply focus-visible:border-inherit; } [type='checkbox'], [type='radio'] { @apply focus:ring-cerulean-600; @apply cursor-pointer; } [type='checkbox']:checked, [type='radio']:checked { @apply bg-cerulean-600; @apply focus-visible:bg-cerulean-600; @apply focus:bg-cerulean-600; @apply hover:bg-cerulean-600; } select { @apply focus:ring-2; @apply focus:outline-none; @apply focus:ring-cerulean-600; @apply focus:ring-offset-2; @apply focus:border-inherit; } [type='submit'] { @apply px-6; @apply text-lg; @apply tracking-widest; @apply bg-cerulean; @apply text-white; } } Assuming you're a developer- get creative, build something, find a workaround. It's part of the job. After 10 years I would think that you'd have more of a "I gave this a shot but couldn't get it to work" approach to the question, especially given that the members of the PW forums are overwhelmingly positive and here to help.
    3 points
  47. @adrian You're absolutely right, poor choice of words. I should have said "universally available and free" rather than "already installed". The point was about accessibility vs paid solutions, but I'll fix the wording. Thanks! @Gideon So ๐Ÿ˜„ Fair enough! Though getting them to install a free app is still easier than explaining monthly SMS fees to the client!
    3 points
  48. Thx! seems I forgot this one. Will fix this after my vacation ๐Ÿ˜Š Thx @cwsoft still here just not as active as before. It has always been a dream to push things forward and spend even more time with PW and provide top notch quality and support. but I realised I'm on very thin ice. Also I was really really busy with my startup which we launched last October ๐Ÿ˜Š thx for your wishes! Greatly appreciated (and needed ๐Ÿ˜…)
    3 points
  49. @wbmnfktr Thanks, that is a good point. Now i show a filelist and updated the text: Is now implemented, thanks for this. That's a great suggestion! I actually had the same idea, but I haven't found the time to implement it yet. It's definitely on my to-do list for a future update! I made it available on GitHub: https://github.com/markusthomas/ProcessWireKickstart
    3 points
  50. Awesome! Yes, Opus 4.5 is really good now with PW. It also helps a lot that they have implemented the LSP in Claude Code directly. Honestly, at this stage I don't think we even need to feed docs to it anymore. Just instructions to explore the relevant API methods for a task itself itself in the codebase. Is there a specific reason why you implemented that as MCP and not as Skill? MCPs eat a lot of context. Depends on the implementation, of course. So dunno about how much context Octopus occupies. ATM I have some basic instructions in CLAUDE.md that explain how to bootstrap PW and use the CLI through ddev for exploration, debugging, DB queries. That makes a big difference already. Opus is great at exploring stuff through the PHP CLI, either as one-liners or as script files for more complex stuff. Here's my current instructions: ## PHP CLI Usage (ddev) All PHP CLI commands **must run through ddev** to use the web container's PHP interpreter. ### Basic Commands ```bash # Run PHP directly ddev php script.php # Check PHP version ddev php --version # Execute arbitrary command in web container ddev exec php script.php # Interactive shell in web container ddev ssh ``` ### ProcessWire Bootstrap Bootstrap ProcessWire by including `./index.php` from project root. After include, full PW API is available (`$pages`, `$page`, `$config`, `$sanitizer`, etc.). **All CLI script files must be placed in `./cli_scripts/`.** **Inline script execution:** ```bash ddev exec php -r "namespace ProcessWire; include('./index.php'); echo \$pages->count('template=product');" ``` **Run a PHP script:** ```bash ddev php cli_scripts/myscript.php ``` **Example CLI script** (`cli_scripts/example.php`): ```php <?php namespace ProcessWire; include(__DIR__ . '/../index.php'); // PW API now available $products = $pages->find('template=product'); foreach ($products as $p) { echo "{$p->id}: {$p->title}\n"; } ``` ### PHP CLI Usage for Debugging & Information Gathering Examples **One-liners** โ€” use `ddev php -r` with functions API (`pages()`, `templates()`, `modules()`) to avoid bash `$` variable expansion. Local variables still need escaping (`\$t`). Prefix output with `PHP_EOL` to separate from RockMigrations log noise: ```bash # Count pages by template ddev php -r "namespace ProcessWire; include('./index.php'); echo PHP_EOL.'Products: '.pages()->count('template=product');" # Check module status ddev php -r "namespace ProcessWire; include('./index.php'); echo PHP_EOL.(modules()->isInstalled('ProcessShop') ? 'yes' : 'no');" # List all templates (note \$t escaping for local var) ddev php -r "namespace ProcessWire; include('./index.php'); foreach(templates() as \$t) echo \$t->name.PHP_EOL;" ``` **Script files** โ€” preferred for complex queries, place in `./cli_scripts/`: ```php // cli_scripts/inspect_fields.php <?php namespace ProcessWire; include(__DIR__ . '/../index.php'); $p = pages()->get('/'); print_r($p->getFields()->each('name')); ``` ```bash ddev php cli_scripts/inspect_fields.php ``` ### TracyDebugger in CLI **Works in CLI:** - `d($var, $title)` โ€” dumps to terminal using `print_r()` for arrays/objects - `TD::dump()` / `TD::dumpBig()` โ€” same behavior **Does NOT work in CLI:** - `bd()` / `barDump()` โ€” requires browser debug bar **Example:** ```php <?php namespace ProcessWire; include(__DIR__ . '/../index.php'); $page = pages()->get('/'); d($page, 'Home page'); // outputs to terminal d($page->getFields()->each('name'), 'Fields'); ``` ### Direct Database Queries Use `database()` (returns `WireDatabasePDO`, a PDO wrapper) for raw SQL queries: ```php <?php namespace ProcessWire; include(__DIR__ . '/../index.php'); // Prepared statement with named parameter $query = database()->prepare("SELECT * FROM pages WHERE template = :tpl LIMIT 5"); $query->execute(['tpl' => 'product']); $rows = $query->fetchAll(\PDO::FETCH_ASSOC); // Simple query $result = database()->query("SELECT COUNT(*) FROM pages"); echo $result->fetchColumn(); ``` **Key methods:** - `database()->prepare($sql)` โ€” prepared statement, use `:param` placeholders - `database()->query($sql)` โ€” direct query (no params) - `$query->execute(['param' => $value])` โ€” bind and execute - `$query->fetch(\PDO::FETCH_ASSOC)` โ€” single row - `$query->fetchAll(\PDO::FETCH_ASSOC)` โ€” all rows - `$query->fetchColumn()` โ€” single value **Example** (`cli_scripts/query_module_data.php`): ```php <?php namespace ProcessWire; include(__DIR__ . '/../index.php'); $query = database()->prepare("SELECT data FROM modules WHERE class = :class"); $query->execute(['class' => 'ProcessPageListerPro']); $row = $query->fetch(\PDO::FETCH_ASSOC); print_r(json_decode($row['data'], true)); ``` ### ddev Exec Options - `ddev exec --dir /var/www/html/site <cmd>` โ€” run from specific directory - `ddev exec -s db <cmd>` โ€” run in database container - `ddev mysql` โ€” MySQL client access
    3 points
ร—
ร—
  • Create New...