Why MediaHub?
A shared media library changes how you think about images. Instead of uploading the same photo five times to five pages, you upload once and reference everywhere. Here's what that means in practice.
Built on ProcessWire, not around it
MediaHub is a ProcessWire-native media library. It doesn't work around the core or replace anything; it uses ProcessWire's own page reference system (FieldtypePage) to build a structured, shared asset library with a dedicated admin interface on top.
ProcessWire's architecture already makes a shared media library possible. You could create a "media" branch in your page tree, store images there as pages, and reference those pages from any template using a standard page reference field. MediaHub formalises that pattern and wraps it in a purpose-built UI with upload management, crop editing, usage tracking, tags, collections, and a picker modal, so you don't have to build and maintain it yourself.
When a shared library makes sense
ProcessWire's native image field (FieldtypeImage) is the right tool for page-specific content, a blog post's featured image, a team member's headshot, a product photo that belongs to one product page. Files are stored per-page, and that's exactly the right behaviour for genuinely page-specific assets.
| Native image field (typical setup) | MediaHub |
|---|---|
| Same image on 5 pages = 5 uploads (potentially) | Upload once, reference from any number of pages |
| Alt text set per image instance on each page | Centralised alt text, set once on the asset |
| No built-in usage tracking | Every reference is tracked: see where every asset is used |
| No library UI; editors browse per-page | Searchable, filterable library with tags and collections |
| Crops stored as per-page image variations | Crops stored once in the library, selectable from any field |
| Separate field types for images vs documents | Images, PDFs, audio, and video in one field type |
ProcessWire's page reference system can already be used to share media across pages; MediaHub is built on exactly that foundation. The table above reflects the common pattern when using standard image fields in a typical per-page setup.
A shared library starts making more sense when:
- The same image needs to appear in multiple places: a logo, a brand image, a venue photo used across many event pages
- Alt text should be consistent everywhere the image appears, not set independently on each page
- You want to know where a specific file is used before deleting or replacing it
- Editors need to browse and reuse existing assets without re-uploading
- Editorial crops (not just automated resizes) should be prepared once and reused across pages
None of this is impossible with native ProcessWire; it just requires building and maintaining the infrastructure yourself. MediaHub provides it ready to go.
MediaHub creates new pages for your assets. Every image, document, or file in the MediaHub library is its own ProcessWire page with dedicated storage under site/assets/files/. Your existing site images do not automatically appear in MediaHub. To bring them in, you use the import tools, which copy each image into the library as a new asset page. See the Migration Guide for a step-by-step approach to transitioning an existing site.
How MediaHub uses ProcessWire
Everything MediaHub does is standard ProcessWire:
- Assets are pages (using a custom
PkdMediahubAssetPagepage class) - Crops are pages (using
PkdMediahubCropPage) - Collections are pages (using
PkdMediahubCollectionPage) - Fields on your templates are standard
FieldtypePagepage reference fields - The
image()method returns a standardPageimage: every native PW image method works identically
The admin interface (Setup → Media Hub) is a Process module, and the field picker is a standard Inputfield. If you know ProcessWire, there's nothing foreign here.
Custom page classes
Full transparency: custom page classes are not something I have used extensively in my own ProcessWire projects before MediaHub. This section was written with the help of AI, so if anything here doesn't check out, Ryan's guide is the definitive reference. I'd rather be upfront about that than pretend I can offer deep support on the topic.
MediaHub takes advantage of ProcessWire's custom page classes to give each asset type its own clean PHP API. Rather than working with a generic Page and accessing raw field values by name, you get purpose-built methods like $asset->image(), $asset->isDocument(), $asset->crops(), and $asset->altText() directly on the page object.
Three custom page classes power the API:
| Class | Template | What it represents |
|---|---|---|
PkdMediahubAssetPage | pkd-mediahub-asset | An individual asset (image, document, audio, or video) |
PkdMediahubCropPage | pkd-mediahub-crop | A cropped version of an image asset |
PkdMediahubCollectionPage | pkd-mediahub-collection | A collection (folder/album) grouping assets together |
There is also a custom MediaHubPageArray that extends ProcessWire's PageArray, adding methods like getTag(), findTag(), and description() for working with multi-value MediaHub fields.
Why this matters in practice
Without custom page classes, working with a MediaHub asset would mean accessing raw internal field names:
// Without custom page classes (raw field access)
$asset = $page->hero;
$images = $asset->get('pkd_mediahub_image');
$img = $images->first();
$alt = $asset->get('pkd_mediahub_alt');
$mime = $asset->get('pkd_mediahub_mime');
if (strpos($mime, 'image/') === 0) {
echo "<img src='{$img->url}' alt='{$alt}'>";
}
With the custom page classes, the same thing becomes:
// With custom page classes
$asset = $page->hero;
if ($asset->isImage()) {
echo "<img src='{$asset->image()->url}' alt='{$asset->altText()}'>";
}
The practical benefits go beyond cleaner syntax:
- IDE autocompletion: type
$asset->and your IDE lists every available method. No need to look up field names. - Complex operations as one-liners:
$asset->ensureCropImage('square')checks for an existing crop, creates a centred one if none exists, saves the crop page, and returns the image. That logic would be 20+ lines without the page class. - Type safety in your own code: you can type-hint
PkdMediahubAssetPagein your functions, so PHP rejects anything that is not a MediaHub asset. Without page classes, the best you could do isPage, which accepts any page in the tree. - Stable API: your template code calls
$asset->altText(), not$asset->get('pkd_mediahub_alt'). If an internal field name changes in a future version, your code keeps working.
For more on how custom page classes work in ProcessWire, Ryan Cramer's comprehensive guide covers everything from basic usage to advanced patterns like inheritance, interfaces, and helper classes.
Crops: centralised vs per-page
If you've used a per-page cropping module before, it's worth understanding how MediaHub's approach differs: not because one is better in all cases, but because the trade-offs are different depending on your project.
With per-page cropping modules, crops are stored alongside the source image on each page. Each page manages its own cropped versions, and presets are typically defined in the template field configuration. This is a solid model and works well when crops are genuinely page-specific.
With MediaHub, a crop is created once in the library and stored as a separate page with its own ID. That crop page can then be selected from any field on any page; no per-page regeneration needed. Because a crop is a page, it can be independently selected, tracked, and referenced just like any other asset.
| Per-page cropping | MediaHub |
|---|---|
| Crop presets defined in template field config | Crops created freely in the library admin |
| Crop stored per-page alongside the source image | Crop stored once as a library page, reused everywhere |
| Same preset applies to all pages using that template | Any field on any page can select any crop in the library |
| A crop is a derived image variation | A crop is a first-class page with its own ID |
If your crops are strictly per-template and don't need to be shared, a per-page approach is simpler. If you need editorial crops prepared once and reusable across pages and templates, MediaHub's library model is a better fit.
Is MediaHub right for your project?
MediaHub adds a layer of indirection: instead of $page->image returning a Pageimage directly, you get an asset page and call $asset->image(). For very simple sites with page-specific images and no reuse requirements, native image fields are the right choice and simpler to work with.
MediaHub earns its place when you have meaningful asset reuse across pages, need a browsable library with search and organisation, want usage tracking, or need editorial crops to be prepared once and referenced anywhere.