Skip to content

Twig Media Reference

The media adapter provides URL generation for images (with ImageWorks transformations), gallery images, file downloads, and streaming. For rendering images as HTML, see cms.render.

Image functions take three separate arguments: the object, image transform options, and collection context. These are separate objects — do not merge them.

cms.media.imagePath(object, {transforms}, {context})
│ │ │
│ │ └── collection, property
│ └── w, h, fit, fm, etc.
└── object ID or full object

Get the ImageWorks API URL for an image. Use this when you need just the URL (not a full <img> tag).

{# Basic image URL #}
<img src="{{ cms.media.imagePath('hero') }}" alt="Hero">
{# With ImageWorks transformations #}
<img src="{{ cms.media.imagePath('hero', {w: 800, h: 600, fit: 'crop'}) }}">
{# WebP format #}
<div style="background-image: url('{{ cms.media.imagePath('bg', {w: 1920, fm: 'webp'}) }}')"></div>
{# Custom collection and property — note: separate argument from transforms #}
{{ cms.media.imagePath('widget', {w: 400}, {collection: 'products', property: 'photo'}) }}
{# Pass object directly (avoids re-fetching) #}
{{ cms.media.imagePath(product, {w: 600}, {collection: 'products', property: 'image'}) }}
ParameterTypeDefaultDescription
idOrObjectstring|array|nullrequiredObject ID or full object data
imageworksarray[]ImageWorks transformation parameters (w, h, fit, fm, etc.)
optionsarray[]Collection context: collection, property

For available ImageWorks parameters, see the ImageWorks Reference.

Images stored inside a card or deck field are addressed through the property option using a dot-notation path. The first segment is the parent property; subsequent segments walk down to the image.

{# Card child — `mycard` is the card field, `image` is the child key #}
{{ cms.media.imagePath('post-1', {}, {property: 'mycard.image'}) }}
{# Deck child — `mydeck` is the deck field, `item-3` is the deck-item id, `image` is the child key #}
{{ cms.media.imagePath('post-1', {}, {property: 'mydeck.item-3.image'}) }}
{# Same syntax works when passing the object directly #}
{{ cms.media.imagePath(post, {w: 800}, {property: 'mycard.image'}) }}

The dot-notation maps directly to URL segments — mycard.image becomes /imageworks/{coll}/{id}/mycard/image.{format} — and the image data is resolved by descending the same path on the object (obj.mycard.image).

The same syntax works on the corresponding render macro:

{{ cms.render.image('post-1', {w: 800}, {property: 'mycard.image'}) }}

The Image Builder dialog (the imageworks utility opened from the admin form) detects nested images and shows the dotted-property macro in its “Copy macro” section, so you can copy a working snippet directly.

Get the ImageWorks API URL for a specific gallery image.

{# By filename #}
<img src="{{ cms.media.galleryPath('vacation', 'sunset.jpg', {w: 800}) }}">
{# Dynamic selectors #}
<img src="{{ cms.media.galleryPath('vacation', 'first', {w: 400}) }}">
<img src="{{ cms.media.galleryPath('vacation', 'featured', {w: 400}) }}">
{# Custom collection #}
{{ cms.media.galleryPath('widget', 'front.jpg', {w: 300}, {collection: 'products'}) }}
ParameterTypeDefaultDescription
idOrObjectstring|array|nullrequiredObject ID or full object data
namestring|int|nullrequiredFilename, index, or dynamic selector (first, last, random, featured)
imageworksarray[]ImageWorks transformation parameters
optionsarray[]Options: collection, property

Get the complete image data object for a specific gallery image. Returns null if not found.

{% set imgData = cms.media.galleryImageData('vacation', 'sunset.jpg') %}
{% if imgData %}
<p>{{ imgData.alt }}</p>
<p>{{ imgData.width }}x{{ imgData.height }}</p>
{% endif %}
ParameterTypeDefaultDescription
idOrObjectstring|arrayrequiredObject ID or full object data
namestring|intrequiredFilename or index
optionsarray[]Options: collection, property

Downloads use Content-Disposition: attachment to force the browser download dialog.

Get the download URL for a file property.

<a href="{{ cms.media.download('report') }}">Download Report</a>
{# Custom collection and property #}
<a href="{{ cms.media.download('doc', {collection: 'documents', property: 'pdf'}) }}">Download PDF</a>
{# Password-protected #}
<a href="{{ cms.media.download('doc', {pwd: 'secret123'}) }}">Download</a>
{# Card child — `mycard` is the card field, `file` is the child key #}
<a href="{{ cms.media.download('post-1', {property: 'mycard.file'}) }}">Download</a>
{# Deck child — `mydeck` is the deck field, `item-3` is the deck-item id, `file` is the child key #}
<a href="{{ cms.media.download('post-1', {property: 'mydeck.item-3.file'}) }}">Download</a>

The dot-notation maps directly to URL segments — mycard.file becomes /download/{coll}/{id}/mycard/file — and the file data is resolved by descending the same path on the object (obj.mycard.file). The File Links dialog in the admin form detects nested files and shows the dotted-property macro in its “Copy macro” section.

ParameterTypeDefaultDescription
idOrObjectstring|arrayrequiredObject ID or full object data
optionsarray[]Options: collection, property, pwd

Get the download URL for a specific file in a depot.

{% set files = cms.media.depot('documents') %}
{% for file in files %}
<a href="{{ cms.media.depotDownload('documents', file.name) }}">{{ file.name }}</a>
{% endfor %}
{# File in a subfolder #}
{{ cms.media.depotDownload('docs', 'report.pdf', {path: 'reports/2024'}) }}
{{ cms.media.depotDownload('docs', 'reports/2024/report.pdf') }}
{# Password-protected #}
{{ cms.media.depotDownload('docs', 'secret.zip', {pwd: 'pass123'}) }}
ParameterTypeDefaultDescription
idOrObjectstring|arrayrequiredObject ID or full object data
namestringrequiredFilename
optionsarray[]Options: collection, property, path, pwd

Streaming uses Content-Disposition: inline and supports HTTP range requests, making it ideal for video and audio playback.

Get the stream URL for a file property.

<video controls>
<source src="{{ cms.media.stream('intro-video') }}" type="video/mp4">
</video>
<audio controls>
<source src="{{ cms.media.stream('podcast') }}" type="audio/mpeg">
</audio>
{# Custom collection #}
{{ cms.media.stream('clip', {collection: 'videos', property: 'video'}) }}
{# Password-protected #}
{{ cms.media.stream('clip', {pwd: 'secret123'}) }}
{# Card or deck child — same dot-notation as `download()` #}
{{ cms.media.stream('post-1', {property: 'mycard.file'}) }}
{{ cms.media.stream('post-1', {property: 'mydeck.item-3.file'}) }}
ParameterTypeDefaultDescription
idOrObjectstring|arrayrequiredObject ID or full object data
optionsarray[]Options: collection, property, pwd

Get the stream URL for a specific file in a depot.

<video controls>
<source src="{{ cms.media.depotStream('media', 'intro.mp4') }}" type="video/mp4">
</video>
{# File in a subfolder #}
{{ cms.media.depotStream('media', 'movie.mp4', {path: 'videos'}) }}
{{ cms.media.depotStream('media', 'videos/movie.mp4') }}
{# Password-protected #}
{{ cms.media.depotStream('media', 'audio.mp3', {pwd: 'pass123'}) }}
ParameterTypeDefaultDescription
idOrObjectstring|arrayrequiredObject ID or full object data
namestringrequiredFilename
optionsarray[]Options: collection, property, path, pwd

Get the list of files in a depot property.

{% set files = cms.media.depot('documents') %}
{% for file in files %}
<p>{{ file.name }} ({{ file.size }} bytes)</p>
{% endfor %}
ParameterTypeDefaultDescription
idstringrequiredObject identifier
optionsarray[]Options: collection, property
StreamDownload
Content-Dispositioninlineattachment
Range requestsYesNo
Best forVideo, audio, PDFs in-browserFiles to save locally
Password supportYesYes