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, 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 tags (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 tags (global label on the asset):
$asset->hasTag('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/
$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.

Tags

MediaHub has two separate tagging systems. Library tags are used by editors to sort and manage assets in the MediaHub library. Display tags are what you might be more familiar with as a developer: 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 tags describe what an asset is. Assigned to an asset on its detail page in the MediaHub library, they exist to help library users organise assets. Tags are automatically added to a dropdown filter called Tags in the library toolbar and are used for convenience of library organisation, filtering and display in the back-end. Because they live on the asset itself, they are global: tag an image "landscape" and that tag is true on every page that references it. 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 tag "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 tag, different display tag on each page.

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

MethodReturnsDescription
$asset->tags()PageArrayAll tags assigned to this asset.
$asset->hasTag('landscape')boolCheck by title or page ID.
// Filter by tag
foreach ($page->gallery as $asset) {
    if ($asset->hasTag('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 tags. 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.

MethodReturnsDescription
$asset->crops()PageArrayAll crop pages for this asset.
$asset->cropCount()intNumber of crops.
$asset->hasCrops()boolWhether any crops exist.
$asset->hasCrop('square')boolWhether a crop exists for a specific preset.
$asset->getCrop('square')PageThe crop page for a preset (or NullPage).
$asset->getCropsByPreset('square')PageArrayAll crop pages for a preset (there may be more than one).
$asset->cropImage('square')Pageimage|nullThe crop's image directly, skipping the intermediate page.
$asset->cropImage('16_9', 800, 450)Pageimage|nullCrop image resized to specific dimensions.
$asset->ensureCropImage('square')Pageimage|nullLike cropImage(), but auto-generates a centred crop if none exists. The generated crop is a real crop page: it appears in the asset's Crops table in the admin and can be adjusted by an editor. Never overwrites an editor-curated crop.

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 centred 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>";
    }
}