Leaderboard
Popular Content
Showing content with the highest reputation on 06/04/2026 in Posts
-
Hey everyone, MediaHub 1.19.0 is ready. That is good news for two reasons: you might find it useful, and you might be too distracted to wonder where 1.18 went. 🙂 Anywho, MH 1.19 has two main areas of improvement: the main MediaHub library screen (for editors) a new read API for galleries at scale (for developers). MediaHub Library changes A) Redesigned sidebar The sidebar has been redesigned and refined, with new shortcut filters at the top B) Favourites Mark any asset as a favourite (site-wide) and filter the library to favourites only. You can favourite from the asset detail page, the tile menu, or by dragging tiles onto Favourites in the sidebar. I am still debating Favourite/unfavourite vs star/unstar for the wording. Open to opinions there. C) Recent See your newest uploads and choose what “recent” means: last 24 hours, last 7 days, and other presets. More flexibility planned here soon. D) Filter breadcrumb type thing When you filter the library, a breadcrumb-style trail shows where you are (for example All Assets › Labels: Dublin). Clear a filter with one click instead of guessing how you narrowed the view. E) Labels If you use Labels for organisation, they are now a first-class shortcut in the sidebar, with counts per label. The section collapses when you do not need it. Drag assets onto a label row to assign in bulk; rename or delete from the row menu. F) Hover info on asset cards Hover over an asset to quickly see the title and filename without turning on Details view or opening the full asset page. This way, you get a really clean Library grid and still benefit from an in-betweeny view. G) Favourites (pt2) You can mark an asset as a favourite from the assets card/panel. Admittedly, 'unfavourite' is a little awkward-sounding. How does it read in German, Austrian, Bulgarian, Irish? I'll find out shortly. I might change this to star/unstar. MediaHub - drag and drop Another gap closed. You can drag and drop assets directly onto a MediaHub field. If you want to disable that function, you can do it on a field-by-field basis. You can also re-order assets as per the native input field. And if you're not a drag-and-drop fan, you can use the buttons instead. The MediaHub button will open your Library. Upload button opens your Finder. Uploads and drag-and-drop currently land new files in the root of the library in the background. I am planning more flexibility there soon. getRaw () API (beta) I'll be straight: I have not fully tested this myself on production sites yet, but I did run it through rigorous automated test scripts, and the performance benefits look promising. There is a more comprehensive write-up in the MediaHub docs. And I want to thank @David Karich for pushing this feature forward and flagging the original limitation in the first instance. Not strictly 1.19 related Search the docs The MediaHub documentation has a new search box in the sidebar Limitations and planned improvements Created a page with the known gaps in MediaHub. This is going to be a living (but rapidly shrinking) list as I move towards MediaHub 1.20.X. Get 1.19: About MediaHub: https://www.peterknight.digital/products/mediahub/ Upgrade to 1.19: https://www.peterknight.digital/downloads/mediahub/ Read the blog: https://www.peterknight.digital/blog/posts/mediahub-1-19-release/ Full changelog: https://www.peterknight.digital/docs/mediahub/v1/changelog/ Cheers 🍻 Peter5 points
-
New Figma to PageGrid Importer From design to production in no time, with the new Figma to PageGrid Importer. At our studio, Konkat, we do all our design work in Figma because it lets us move and iterate quickly alongside our clients. While AI is great at spinning up generic, cookie-cutter layouts, true professional value lies in creating websites genuinely custom-tailored to a client. For that level of work, pure text prompts simply don’t offer the layout precision you need—writing a description will never match the intuitive control of direct visual input. But as any developer here knows, turning a finished design into a live, client-editable website usually requires a lot of manual layout replication before you can get to the core development. Even though PageGrid is already a massive speed upgrade, manually recreating a canvas layout element-by-element is still a time-consuming assembly phase. It eats up hours better spent on deep development, custom logic, and polished execution. That’s exactly why I (with the help of Claude Code) built the new Figma Exporter plugin and a native PageGrid Importer module for ProcessWire. It compresses hours of manual layout replication into a five-second automated import. By handling the structural translation instantly, it lets you skip the repetitive setup entirely and jump straight into the fun stuff: custom animations, fine-tuning, and high-level development. Instead of just telling you what it does, I want to be completely transparent about how it was built, why we intentionally avoided a "live AI" generation solution, and how it changed my perspective on building dev tools. Why We Rejected Live AI Generation When I started working on this, my first instinct was to leverage the power of AI agents directly during the import process. I tried using Claude via a live Model Context Protocol (MCP) setup to directly read my active Figma canvas and dynamically generate the PageGrid layout on the fly. Honestly, AI is surprisingly good at understanding how to build a layout in PageGrid now, and the initial results were already incredibly close to the original Figma designs. Using MCP is a really interesting alternative, but for daily production work, relying on a live AI connection just didn't make sense for a few major reasons: It was unpredictable: Every single time I ran the generation on the exact same layout, the resulting code structure came back slightly different. It was slow: Relying on live AI cloud prompts meant waiting for the model to think, stream, and process the data. API Bottlenecks: The live Figma API connections generated far too many requests, causing frequent rate-limiting issues. Resource-heavy: Each time we want to create a new layout we have to prompt an AI, which uses extra computing power and adds up in ongoing token costs. At our agency, Konkat, we built PageGrid to power actual production sites for our clients. We plan to use these tools daily to optimize our own studio workflow. In a professional production pipeline, an unpredictable guessing game that changes its behavior on every prompt simply isn't an option. We needed something that was completely deterministic, blazing fast, and independent of live external APIs. So, we changed our strategy entirely. Changing the Strategy: AI as the Engineer, Not the Runtime Since Claude had become deeply familiar with the Figma API, and thoroughly understood the structure of ProcessWire and PageGrid, I stopped trying to use the AI to generate layouts on the fly. Instead, I partnered with Claude to write a dedicated, local compiler. Claude acted as my co-developer. Together, we built a simple, two-part ecosystem: A local Figma Exporter Plugin that reads the canvas instantly and packages the architectural structure and assets into a lightweight .ZIP file. A native ProcessWire Importer Module that unzips that package and handles the rendering locally on your server. Because the final tool runs entirely on pure, local code logic, it requires zero active AI API calls, runs instantly, and produces the exact same, predictable structure every single time. Respecting Layout Intent Without Forcing "Auto Layout" Most Figma-to-code plugins fail unless you have meticulously built your file using strict, perfectly nested Auto Layout components. If you design loosely, those plugins break or output absolute-positioned spaghetti code that is impossible to maintain. As a designer, I know that forcing strict Auto Layout workflows during the rapid, creative prototyping phase can feel incredibly restrictive. That’s why we engineered our importer to give you complete freedom to design your way. Whether you prefer nesting elements using strict Auto Layout, arranging them freely using Figma's native Column Layout Guides, or using a mix of both, the compiler adapts to your workflow. When you run the importer, PageGrid respects your structural intent and translates it into standard web architecture: Native CSS Grid & Flexbox: Elements aligned to your column guides are automatically mapped to precise, responsive CSS Grid positions, while Auto Layout frames are translated cleanly into semantic Flexbox structures. Direct Layer Mapping & Smart Flattening: The importer replicates your Figma layer structure directly in PageGrid by mapping all layer nodes straight to native PageGrid Blocks like pg_group (groups), pg_image (images), and pg_editor (text). At the same time, the parser automatically filters the tree, flattening out any unnecessary deep nesting or arbitrary wrappers when needed so your backend tree stays incredibly clean. Maps Figma API to Modern CSS: It natively extracts typography styles, colors, borders, spacing rules, and effects, turning them directly into clean PageGrid metadata or copyable CSS. 💡 The "Grouping" Pro-Tip: Because Figma group nodes map directly to pg_group container blocks, grouping items that belong together directly shapes your PageGrid backend structure. While the importer can handle ungrouped layers, grouping your elements ensures the highest layout accuracy and keeps complex structures beautifully organized under the hood. Keeping You in the Driver's Seat When the import finishes, you are not left with a static image or a fragile webpage that breaks the moment you edit a line of text. You get a native, fully editable ProcessWire page built out of organized PageGrid blocks. Because PageGrid functions like a precise web canvas, the layout remains rock-solid. Your clients can easily log in to update text and images directly on the live page, but they will never accidentally break the structural layout you designed. The mechanical translation work is completed in five seconds. From there, you take over to do the work that humans do best: adding fine-tuned interactions, implementing custom animations, and binding dynamic backend data fields. How to Try It You don't need a paid plan to use it—the plugin works perfectly on the free version of Figma. Here is how to get started: Get the Figma Plugin: Open the Figma to PageGrid Exporter in Figma. Select your main design frame and download your .ZIP package. Install the Importer Module (Self-Hosted Only): Add the PageGridFigmaImport module to your ProcessWire backend. Upload & Run: Go to Setup > Figma to PageGrid, drop in your file, and watch your layout appear natively. Documentation: Figma Import Documentation. I consider this a beta launch, not every generated layout will be perfect out of the box, but results so far have been quite impressive. I plan to improve this over time. Give it a try and let me know what you think!4 points
-
For all who are interested in this module: I have been a tester in the past and this module is excellent. I am using it now in every project at it makes asset handling (not only images but think of pdf, mp3, video, etc.) a breeze. This module acts as a missing link for global media management in ProcessWire.3 points
-
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, Mike2 points
-
I couldn't agree with this "love letter" any more than the others already have! When we explored the possibilities of SiteSync, the interplay with RockMigrations and coding agents opened up an incredibly fascinating workflow that we wouldn't want to do without anymore. Our front-end and back-end developers have barely needed to talk to each other since. 😅 Fantastic module, thanks a lot, @bernhard!1 point
-
FYI https://processwire.com/talk/topic/30747-using-ai-to-migrate-your-migrations-tutorial-kind-of/ https://processwire.com/talk/topic/31575-using-config-migrations-with-an-existing-project/1 point
-
@HMCB ChatAI will only suggest pages the user can access by role. Additional limits can be by template and/or a checkbox on a page template.1 point
-
@psy This is awesome. Question: Seeing that it can be used on the front-end, are we able to control what content the chat has access to? For instance, depending on the logged-in user, I may only want the chatbot to access certain pages (and sub pages) in a given site.1 point
-
Hi everyone, a client of ours had a term that shows up all over their site, and they had it registered internationally. So suddenly it needed an ® after every occurrence. The question landed in our inbox as "you probably know an easy way to do this, right?" 😉 There is already Ryan's TextformatterFindReplace, which is powerful and the right tool if you are happy writing regex. We needed something different: a textformatter our clients can edit themselves, i.e. people who do not write regular expressions. So in Annotations you just list the strings and pick options in a small per-string table, no regex anywhere. And so clients never have to touch the Modules section, the module also adds its own page under Setup, guarded by a dedicated annotations-edit permission, where they manage exactly these settings and nothing else. What it can do, for example: Append a mark, the classic case: put (R) (or ©, ™, ...) after a term wherever it appears. Wrap a part of a word, e.g. turn H2O into H2O (subscript the 2). Auto-style certain terms, e.g. make a brand name bold everywhere. Footnote markers, mark only the first occurrence of a term (first-only), great for footnotes1. The real work, though, is in the details that make it safe to hand to an editor: It only changes text, never markup. Tags and their attributes (href, alt, title, class), HTML comments, and the content of skip-tags you configure (code, pre, script, style) are left completely alone. A brand name sitting in a URL or an alt text stays untouched. E-mail addresses are protected. With a frameless to ® rule, info@frameless.at does not turn into info@frameless®.at. It never doubles a mark. It recognises a symbol that is already there, whether it was typed as the literal character (®), as an entity (®, ®, ®, ®, lower or upper case, even with leading zeros), or already wrapped in a tag. No second one gets added. It normalises messy input to your setting. Same spelling, consistent form: a bare symbol gets wrapped, an existing wrapper gets unwrapped (or re-wrapped) if you change the tag later. Editors can be inconsistent and the output still comes out uniform. Longest match wins, and rules compose. Configure both "frameless" and "frameless Media" and each keeps its own treatment. Append runs first, wrap layers on top, so "frameless Media" can be bolded on the word and still get its ® at the end: frameless Media®, while a single "frameless" gets rendered as frameless®. Per-string control: whole-word matching (so cat does not hit category), case sensitivity, and first-occurrence-only, each set per string. Any inline wrap tag: sub, sup, b, strong, em, mark, abbr and more, not just superscript. Get it here https://github.com/frameless-at/TextformatterAnnotations https://processwire.com/modules/textformatter-annotations/ Feedback and ideas welcome. Cheers, Mike!1 point
-
For a number of years we've grappled with how best to implement on-page structured data via JSON-LD. For almost all projects we've ended up using a code-based solution, with a standard JSON-LD output defined for all pages/templates, with any template specific structure defined in the template file (e.g. Article for a post template). This approach isn't particularly malleable, at least not for clients who actually want to implement JSON-LD themselves or via their SEO partners. MarkupJsonldModels is an attempt to find a good solution that's workable for everyone, including AgentTools. It uses the concept of "models" - valid JSON-LD using placeholder tags which resolve to actual page values when output on a rendered HTML page. It allows you to define a default model in the module config, a model for each template (assuming it will be output as HTML), and adds a field (jsonld_model) on installation which you can add to a template to allow a model to be defined per page. As GEO becomes more and more important, this is a module I hope will prove quite useful, however my own motivation for it is more laziness than anything else - I wanted to build something where I could just get an AI Agent to suggest and implement models via Agent Tools! Preliminary tests with this approach have been reasonable, and I can definitely see it being a time saver when I get it integrated into our dev process, and I expect the quality of the JSON-LD will end up significantly better too. However, it doesn't require Agent Tools to work - but an ability to work with JSON is... It is currently in Alpha, as it really hasn't been tested in the wild (just yet). I expect there will be another couple of rounds of dev and improvements once we start using it for existing sites that are current looking for GEO improvements. There's a pretty lengthy README - https://github.com/nbcommunication/MarkupJsonldModels/blob/main/README.md - which is likely a giveaway that I've been using Agent Tools (Claude 4.7) to assist in code and documentation review! Any thoughts and feedback would be much appreciated. Chris1 point
-
Hi everyone, Building a package forwarding platform means dealing with phone numbers from dozens of countries. US customers, European recipients, warehouse staff - each expects a different format. Storing a raw string and hoping for the best doesn't work. This fieldtype does it properly. GitHub: https://github.com/mxmsmnv/FieldtypeTel What it does Powered by intl-tel-input v28 - bundled locally, no CDN dependency. Country flag picker with search Stores four formats per number: e164 - +12025550123 - for tel: links and shipping APIs intl - +1 202-555-0123 - for international display national - (202) 555-0123 - for local display country - us - for filtering and selectors echo $page->phone; // (202) 555-0123 echo $page->phone->e164; // +12025550123 echo $page->phone->country; // us // tel: link echo "<a href='tel:{$page->phone->e164}'>{$page->phone}</a>"; // Selector — find all Australian numbers $pages->find("phone.country=au"); Restrict countries, set preferred countries, per-field defaults Auto-format as user types AdminThemeUikit themed - light and dark mode via --pw-* CSS variables Requirements: ProcessWire 3.0.200+, PHP 8.2+ MIT License.1 point