Jump to content

Recommended Posts

Posted

Hi all — we're putting this one up as a public beta and looking for feedback before we tag a stable release.

Bildschirmfoto2026-06-04um19_57_28.thumb.png.7152a4b19a4941abe8daf5733699392c.png

How it started. Over the past months we've been moving an old blog into a fresh PW site using our own SiteSync module and a Claude Code agent doing most of the migration grunt work. At some point the blog owner mentioned, in that very offhand way clients do, "hey, an image search would be nice." It was Saturday afternoon, so we let the agent build a prototype, pushed it through SiteSync, tested it on the phone an hour later. Worked great. Search results were… not great. But the search wasn't the problem – the underlying data was. Thousands of imported images, almost no descriptions, no tags, no nothing.

So we needed a way to retroactively caption and tag a few thousand images without clicking through hundreds of page edits one by one. Since PW (rightly) attaches images to the pages they belong to, we needed a tool that reaches across the whole install at once and – crucially – can edit metadata in bulk.

Why not the existing modules? We looked at the two obvious candidates:

  • Media Manager by @kongondo – great if you're starting fresh and want a central media hub. But it's its own  storage layer: you upload INTO Media Manager, editors pick FROM Media Manager. Images already sitting on per-page image fields stay invisible to it. Also commercial.
  • MediaLibrary by @BitPoet – adds a MediaLibrary template with its own MediaImages / MediaFiles fields plus a CKEditor picker. Same pattern: a separate page hierarchy you migrate media into.

Both are well-designed for "we want a central media model from day one." Neither helps you when the media is already scattered across lead_image, body_images, gallery,  images_in_some_repeater etc. Migrating that into a different storage layer would have broken the original page model the blog depends on.

So we built Image Library: a Process module that does nothing to your data – it just surfaces a cross-site table view of everything that's already there, with serious bulk editing on top.

The bulk-edit part – the reason this module exists.

Selection as a paintbrush. You tick N rows across any pages, templates and image fields. Then you edit a cell on ANY of those rows — the popup gains an Add / Replace mode picker (tags additionally offer Remove) and the value gets broadcast to the entire selection in one server round.

  • Same row applies to description, tags, every custom subfield, AND the filename (with placeholders: (n), (n2)..(n5) padded counters, (N) total, (t) page title, (d) date, (p) page name, (f) field name → e.g. rename 200 selected files to event-2025-(n3).jpg).
  • Same row applies to delete (one trash click, whole selection gone behind one confirm dialog with a where-used preflight – see below).
  • Edits that push a row OUT of the active filter ("missing tags" → tag assigned → row no longer matches) fade out and drop from the table; counters auto-decrement.

Other highlights:

  • One sortable, paginated, bookmarkable table across every FieldtypeImage field on every page on every template (with config-side blacklists).
  • Inline edit per cell – multilang-aware: language tabs in the popup, all languages committed in one save.
  • Typed widgets per custom subfield: checkbox, date, integer, options (single + multi), and FieldtypePage rendered through PW's actually configured Inputfield (PageAutocomplete / PageListSelect / ASMSelect / whatever the field uses) — no re-implementation.
  • Replace image in place (drag-drop or upload icon) – basename stays, variations regen.
  • Renaming an image in the library instantly rewrites every CKEditor/TinyMCE embed of that file across the site — original and all variations, in every language — so links never break, and a summary dialog shows which pages were updated.
  • Delete with where-used preflight: dialog scans every Textarea via $pages->findIDs("field%='/pid/stem.', include=all") and lists the pages where the image is still embedded in rich text – CKEditor + TinyMCE both, multilang-aware, with direct edit links so you can fix embeds before deleting.
  • JSON / CSV export + import for offline metadata work – hand a CSV to a copywriter or feed it to your agent, get it back, import it.
  • View prefs (columns, page size, bookmarks) live in $user->meta, cross-device.

Status. v0.54.x – public beta. Module + docs (EN + DE concept) at GitHub or the Modules Directory

Feedback welcome – especially edge cases we haven't seen yet (weird Fieldtype combos in custom-field templates, ProFields, Repeaters / RepeaterMatrix nesting). And if you've got a use case the current feature set doesn't cover, let us know.

Cheers, Mike
 

  • Like 10
  • Thanks 2
Posted

New version (v 0.55.0) – This changes everything

Barely a week on from the public beta release here's where Image Library went next. Short version: it grew a brain for duplicates, and that quietly changed what the module is for.

How it continued. Barely a week after the first post, a different client site handed us the next problem – and this time it wasn't missing metadata, it was duplication, and a lot of it. ~10,000+ images on the site, of which only ~3,500 were actually unique – meaning roughly 6,500 exact-or-near-duplicate copies of the same pictures scattered across lead_imagebody_images, galleries, repeaters, you name it. Years of "just re-upload it on this page too."

So we went looking for a way to make duplicates stop mattering – without migrating anything. The full rationale is in the repo (docs/deduplication-design.md); the gist:

  • Give every image a content identity – a byte hash (xxh128, md5 fallback), computed lazily and cached by path+size+mtime, with a cheap size/dimension pre-filter so we only hash real candidates.
  • Group identical images into clusters = "this picture, in these K places."
  • Then duplicates become manageable, not just visible: a Duplicates filter, a copy-count badge per image, an expandable cluster in the table (a cluster modal in the gallery), where-used per cluster, and the big one – edit-once-propagate: caption/tag a cluster once, written to all copies. Pure DB writes, fully reversible, zero filesystem risk.
  • Optional, opt-in, reversible disk reclaim: byte-identical copies get hardlinked onto one inode, so 6,500 copies stop costing 6,500× the bytes. Lossless, runs in the background (on save + hourly), with Scan / Re-measure / Revert tools and a live "disk reclaimed" readout. (We tried perceptual near-dup detection too – dHash/pHash — and pulled it: it grouped unrelated photos that merely share a tonal layout. Detection-only, never destructive, and still not trustworthy enough to ship.)

image.thumb.png.9e9677166ef001e6009a4f6a732960d5.png

And then it clicked. What we'd built, almost by accident, was a DAM without the DAM. Strip a digital-asset manager down to what it actually gives you: one logical asset instead of scattered copies, metadata edited once as a single source of truth, a "where is this used," a central place to browse and pick – and storage that doesn't pay for the same file twice. Every one of those falls straight out of the content-identity + cluster technique. The difference: we get it over the images already sitting in native FieldtypeImage fields – the asset layer is synthesised from what's there, not a store you migrate into. No central library, no new page type, no migration, and crucially no template changes. That last part is the whole point: on some of these projects, re-wiring every template and every chunk of content onto a new media model would be a multi-week job and a regression-test nightmare. We just… didn't have to – and the editors get the DAM experience anyway.

A word on MediaHub. If you are starting a fresh project and want a proper central media model from day one, MediaHub is – in our opinion – the best option out there. Huge thanks to @Peter Knight for letting us test it; we're genuinely impressed, it's a lovely piece of work. Different tool, different job: new site → MediaHub. Existing site full of scattered images → this. Image Library isn't trying to change the way PW image handling works; it's a layer over the files, pages, templates, methods and structures you already have.

Which is exactly the rule we build by:

  • must work with existing installations, as-is;
  • plug & play – install, open, done;
  • no rebuild, no migration, no new fields, no template surgery;
  • no new workflow for editors;
  • and – new – front-end-editor capable. BAM. 💥

image.thumb.png.d18de1de9b7dc9457e6d90ac6aa3f82c.png

That last one is the other big addition: two optional, off-by-default picker add-ons:

  • Choose from library – a button on every image field to assign an existing library image without re-uploading (version-aware: inside a page version it lands in that version's folder, and it's deduped on the spot).
  • Insert from library – a button in TinyMCE and CKEditor that drops a library image straight into rich text… and it works in the front-end inline editor (PageFrontEdit) too. Editor live on the page, click, pick, done.

image.thumb.png.e78430d74fbdf5c3d44524acc703fccd.png

Plus, while we were in there:

  • Collections – a hand-picked set of images no filter could reproduce (tick the ones you want, save them as a named tab). Recalled by a tiny ?coll=<id> link – the image list lives in your user profile, not the URL, so a 100-image collection is still a ~12-character link. Add/remove just by clicking a collection's tab while images are selected (the cursor tells you which way it goes), and collections are themselves filterable.
  • Masonry gallery view – height-balanced (shortest-column) packing, natural aspect ratios, hover-revealed selection checkboxes – the same selection that drives bulk edits and collections.

Status. v0.55.0 – public beta on top of the original. Module + docs (EN + DE concept, plus the dedup design doc) on GitHub / the Modules Directory.
As before: feedback very welcome – especially duplication in the wild, odd Fieldtype combos in custom-field templates, ProFields, deep Repeater/RepeaterMatrix nesting, and anything the front-end picker trips over. 

Cheers,
Mike

  • Like 1

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...