Docs MediaHub Version 1.x Template API

Template API

How to work with MediaHub assets in your PHP templates. Getting images, resizing, type checking, metadata, labels, display tags, collections, crops, and common output patterns.

A MediaHub field is a standard ProcessWire page reference field. It returns asset pages (or crop pages) rather than files directly. For images, the one extra step is calling ->image() to get a Pageimage; after that, every native PW image method works identically. For non-image assets, use ->file() for the Pagefile or ->fileUrl() for the download URL.

Every method documented below comes from MediaHub's custom page classes: PkdMediahubAssetPage for assets, PkdMediahubCropPage for crops, and MediaHubPageArray for multi-value fields. These extend ProcessWire's Page and PageArray classes, so all standard PW page methods remain available alongside the MediaHub-specific ones.

Coming from ProcessWire's image API

If you have used ProcessWire's native image fields before, some familiar patterns will not behave as expected with MediaHub. The reason is architectural: MediaHub assets are pages, not files. The one-line summary is that where you previously called methods directly on a Pageimage, you first call ->image() to get one, and then everything works identically.

The comparisons below cover the cases most likely to catch you out.

PW image API$page->images->find('tags=gallery')
What happensReturns nothing. ProcessWire image tags are a plain text string on each image. MediaHub does not use that system. It has two of its own: display tags (per-reference, set in the page editor) and library labels (global labels on the asset, built on PW page references). Neither is selector-filterable.
MediaHub equivalentDisplay tags (role on this page):
$page->gallery->findTag('gallery')

Library labels (global label on the asset):
$asset->hasLabel('gallery')
PW image API$page->gallery->first()->url
What happensReturns the page URL, not the image file URL. first() returns a PkdMediahubAssetPage, and Page::url is the page's path in the site tree.
MediaHub equivalent$page->gallery->first()->image()->url
PW image API$page->gallery->first()->description
What happensReturns empty string. MediaHub asset pages have no field named description; ProcessWire returns empty for undefined page properties.
MediaHub equivalent$page->gallery->first()->altText() or $page->gallery->description($asset) for per-reference overrides
PW image API$page->gallery->first()->size(400, 300)
What happensThrows an exception. size() exists on Pageimage, not on Page.
MediaHub equivalent$page->gallery->first()->image()->size(400, 300) or $asset->sized(400, 300)

In full:

// ProcessWire native image field
$page->images->find('tags=gallery');          // works — filters by image tag string
$page->images->first()->url;                  // works — image file URL
$page->images->first()->description;          // works — image description string
$page->images->first()->size(400, 300);       // works — returns sized Pageimage

// MediaHub field — adjusted equivalents
$page->gallery->findTag('gallery');           // display tags (per-reference, set in page editor)
$page->gallery->first()->image()->url;        // go through image() to get the file URL
$page->gallery->first()->altText();           // asset's global alt text
$page->gallery->first()->image()->size(400, 300); // image() then size()

Once you have a Pageimage from ->image(), every ProcessWire image method works exactly as you would expect: size(), width(), height(), srcset(), and so on.

Single value vs multi-value

How you configured the field determines what it returns:

Field typeReturnsExample
Single pagePkdMediahubAssetPage (or NullPage)$page->hero_image
Multiple pages (PageArray)MediaHubPageArray$page->gallery

Single value

$asset = $page->hero_image;
if ($asset && $asset->id) {
    $img = $asset->image();
    echo "<img src='{$img->url}' alt='{$asset->altText()}'>";
}

Multi-value

foreach ($page->gallery as $asset) {
    $img = $asset->image();
    if (!$img) continue;
    echo "<img src='{$img->url}' alt='{$asset->altText()}'>";
}

Getting the image

MethodReturnsDescription
$asset->image()Pageimage|nullThe primary image. Null if the asset is not an image (e.g. a PDF).
$asset->file()Pagefile|nullThe primary file. Works for all asset types: images, documents, audio, video. For images, checks the image field first, then falls back to the file field.
$asset->fileUrl()stringURL of the primary file, or empty string.

Use image() when you know you're working with images. Use file() when the asset could be any type.

Resizing and the PW image API

Because image() returns a standard Pageimage, every ProcessWire image method works as expected:

$img = $asset->image();

// Resize to exact dimensions
$sized = $img->size(800, 600);

// Resize by width only (height auto)
$wide = $img->width(1200);

// Resize by height only (width auto)
$tall = $img->height(400);

// Responsive srcset
echo $img->srcset('320, 640, 960, 1280');

There is also a convenience method on the asset page itself:

// Equivalent to $asset->image()->size(800, 600)
$sized = $asset->sized(800, 600);

HTML output helper

imgTag() generates a complete <img> element with alt text, optional sizing, and extra HTML attributes:

// Basic: <img src="..." alt="...">
echo $asset->imgTag();

// Sized: <img src="..." alt="..." width="800" height="600">
echo $asset->imgTag(800, 600);

// With extra attributes
echo $asset->imgTag(800, 600, [
    'class' => 'hero-img',
    'loading' => 'lazy',
]);

Alt text is taken from the asset's alt text field, falling back to the page title. Returns an empty string for non-image assets.

Type checking

MediaHub supports images, documents, audio, and video. These methods check the asset's MIME type:

MethodReturns true when
$asset->isImage()MIME starts with image/ (includes SVG)
$asset->isSvg()SVG vector image only
$asset->isRasterImage()Raster image (JPG, PNG, GIF, WebP — not SVG)
$asset->isDocument()MIME starts with application/
$asset->isVideo()MIME starts with video/
$asset->isAudio()MIME starts with audio/
// Render different markup by type
foreach ($page->media as $asset) {
    if ($asset->isImage()) {
        echo "<img src='{$asset->image()->width(600)->url}' alt='{$asset->altText()}'>";
    } elseif ($asset->isDocument()) {
        echo "<a href='{$asset->fileUrl()}'>{$asset->title} ({$asset->extension()})</a>";
    } elseif ($asset->isVideo()) {
        echo "<video src='{$asset->fileUrl()}' controls></video>";
    }
}

Additional introspection methods:

MethodReturnsExample
$asset->mimeType()string"image/jpeg"
$asset->extension()string"jpg"

Metadata

MethodReturnsDescription
$asset->altText()stringThe asset's global alt text, or empty string.
$asset->about()stringThe internal admin note (not for HTML output).
$asset->titlestringThe asset's title (standard PW page property).

Per-reference description

When the same image appears on different pages, you may need a different caption or alt text per page. Two approaches:

// Via the field (multi-value fields)
// Returns the page-level override, or falls back to altText()
$caption = $page->gallery->description($asset);

// Via the asset directly (works for any field type)
$caption = $asset->descriptionFor($page);

// Specify the field explicitly
$caption = $asset->descriptionFor($page, 'gallery');

Full details: Per-Reference Metadata.

Labels and tags

MediaHub has two separate systems. Library labels are for organising your media library. Display tags are per-reference labels like "hero" or "thumbnail" that you assign to images within a field on a specific page, then query in your template code. Both are explained below.

Library labels are for organising and filtering assets in the back-end. Assigned on an asset's detail page, they appear as filters in the library toolbar. Because they live on the asset itself, they are global: label an image "landscape" and that label applies everywhere the asset is referenced. These are a MediaHub concept built on ProcessWire page references. They are not the same as ProcessWire's native image tags, which are plain text strings on each image file. If you have previously tagged images to control front-end display, you are probably looking for Display tags described below. As a developer you might be used to an image field having several images but tagging a subset "hero" or "preview" to pick them out in template code. That is what display tags are for.

Display tags describe the role an asset plays on a specific page. Set in the page editor when you add an image to a MediaHub field, they are per-reference: the same asset can be tagged "hero" on your About page and "thumbnail" on your Blog listing. The asset itself is unchanged.

For example: a photo of your office gets the library label "interior" in the MediaHub admin. On the About page you add it to the gallery field and display-tag it "hero". On the Contact page you add the same photo and display-tag it "secondary". Same asset, same library label, different display tag on each page.

Library label methods are below. Display tag methods are in the Display tags section further down this page.

MethodReturnsDescription
$asset->labels()PageArrayAll labels assigned to this asset.
$asset->hasLabel('landscape')boolCheck by title or page ID.
// Filter by label
foreach ($page->gallery as $asset) {
    if ($asset->hasLabel('featured')) {
        echo $asset->imgTag(1200, 600);
    }
}

Collections

Collections (folders, albums, galleries, depending on your admin label) group assets for organisation. An asset can belong to multiple collections.

MethodReturnsDescription
$asset->collections()PageArrayAll collections this asset belongs to.
$asset->inCollection('branding')boolCheck by name, title, or page ID.
$asset->addToCollection($collection)voidAdd to a collection. Pass a Page or page ID. Saves the asset.
$asset->removeFromCollection($collection)voidRemove from a collection. Saves the asset.

Display tags (per-field)

Display tags are separate from library labels. They are per-reference labels assigned in the page editor for controlling front-end output (e.g. marking one image as "hero" on a specific page). These methods are available on multi-value fields (MediaHubPageArray).

MethodReturnsDescription
$page->gallery->getTag('hero')Page|nullFirst asset with this display tag.
$page->gallery->findTag('diagram')PageArrayAll assets with this display tag.
$page->gallery->getDisplayTags($asset)string[]All display tags for a specific asset.
$page->gallery->hasDisplayTag($asset, 'hero')boolCheck if an asset has a specific display tag.
// Use a display tag to pick the hero image from a gallery
$hero = $page->gallery->getTag('hero');
if ($hero) {
    echo $hero->imgTag(1400, 600, ['class' => 'hero']);
}

Full details: Per-Reference Metadata.

Crops

Each crop is a separate page with its own image file and preset key. Crops are accessed through the parent asset. MediaHub distinguishes between library crops (global, visible in the Crops table) and field-level crops (scoped to a page + field, created by inline crop badges). See Crops API for the full explanation.

Library crop methods

MethodReturnsDescription
$asset->crops()PageArrayAll library crop pages for this asset.
$asset->cropCount()intNumber of library crops.
$asset->hasCrops()boolWhether any library crops exist.
$asset->hasCrop('square')boolWhether a library crop exists for a specific preset.
$asset->getCrop('square')PageThe library crop page for a preset (or NullPage).
$asset->getCropsByPreset('square')PageArrayAll library crop pages for a preset.
$asset->cropImage('square')Pageimage|nullThe library crop's image directly. Lookup only — returns null if no crop exists.
$asset->cropImage('16_9', 800, 450)Pageimage|nullLibrary crop image resized to specific dimensions.
$asset->ensureCropImage('square')Pageimage|nullLike cropImage(), but auto-generates a library crop if none exists, framed around the focus point when one has been moved from centre. Never overwrites an editor-curated crop. Returns null for SVG.

Field-aware lookup

MethodReturnsDescription
$asset->resolvedCropImage('square', $pageId, 'field_name')Pageimage|nullChecks for a field-level crop first, falls back to the library crop, then auto-generates a library crop if neither exists. Use this when the field has inline crop badges and you want to respect the editor's page-specific crop.
$asset->hasFieldCrop('square', $pageId, 'field_name')boolWhether a field-level crop exists for this preset on a specific page + field.
$asset->getFieldCrop('square', $pageId, 'field_name')PageThe field-level crop page (or NullPage).
$asset->getFieldCrops($pageId, 'field_name')PageArrayAll field-level crops for this asset on a specific page + field.

Full details: Crops API.

Common patterns

Hero image with crop fallback

$asset = $page->hero_image;
if ($asset && $asset->id) {
    // Use the 16:9 crop if it exists, otherwise fall back to the original
    $img = $asset->cropImage('16_9', 1400, 788) ?: $asset->image()->size(1400, 788);
    $alt = $asset->descriptionFor($page) ?: $asset->altText();
    echo "<img src='{$img->url}' alt='{$alt}'>";
}

Gallery with lazy crop generation

foreach ($page->gallery as $asset) {
    // ensureCropImage auto-generates a focus-aware square crop on first call
    $img = $asset->ensureCropImage('square', 400, 400);
    if (!$img) continue;
    $desc = $page->gallery->description($asset);
    echo "<figure>";
    echo "  <img src='{$img->url}' alt='{$desc}'>";
    if ($desc) echo "  <figcaption>{$desc}</figcaption>";
    echo "</figure>";
}

Download link for a document

$doc = $page->downloads->first();
if ($doc && $doc->isDocument()) {
    $file = $doc->file();
    echo "<a href='{$file->url}'>Download {$doc->title} ({$doc->extension()}, " .
         number_format($file->filesize / 1024) . " KB)</a>";
}

Mixed media output

foreach ($page->media as $asset) {
    if ($asset->isImage()) {
        echo $asset->imgTag(800, 600, ['loading' => 'lazy']);
    } elseif ($asset->isVideo()) {
        echo "<video src='{$asset->fileUrl()}' controls preload='metadata'></video>";
    } elseif ($asset->isAudio()) {
        echo "<audio src='{$asset->fileUrl()}' controls></audio>";
    } elseif ($asset->isDocument()) {
        echo "<a href='{$asset->fileUrl()}'>{$asset->title}</a>";
    }
}

Last updated