Assets Fields

Assets fields allow you to upload and relate assets to other elements. It is one of Craft’s relational custom fields.

# Settings

Assets fields have the following settings:

  • Restrict uploads to a single folder? – Whether file uploads/relations should be constrained to a single folder.

    If enabled, the following setting will be visible:

    • Upload Location – The location that files dragged directly onto the field should be saved in.

    If disabled, the following settings will be visible:

    • Sources – Which asset volumes (or other asset index sources) the field should be able to relate assets from.
    • Default Upload Location – The default location that files dragged directly onto the field should be saved in.
  • Restrict allowed file types? Whether the field should only be able to upload/relate files of a certain type(s).

  • Limit – The maximum number of assets that can be related with the field at once. (Default is no limit.)

  • View Mode – How the field should appear for authors.

  • Selection Label – The label that should be used on the field’s selection button.

# Multi-Site Settings

On multi-site installs, the following settings will also be available (under Advanced):

  • Relate assets from a specific site? – Whether to only allow relations to assets from a specific site.

    If enabled, a new setting will appear where you can choose which site.

    If disabled, related assets will always be pulled from the current site.

  • Manage relations on a per-site basis – Whether each site should get its own set of related assets.

# Dynamic Subfolder Paths

Subfolder paths defined by the Upload Location and Default Upload Location settings can optionally contain Twig tags (e.g. news/{{ slug }}).

Any properties supported by the source element (the element that has the Assets field) can be used here.

If you want to include the entry’s ID or UID in a dynamic subfolder path, use {canonicalId} or {canonicalUid} rather than {id} or {uid}, so the source entry’s ID or UID is used rather than the those of a draft or revision.

If an Assets field is used on an entry type within a Matrix field, the source element is going to be the nested entry, not the element that the entry belongs to.

In this case, if you wanted to incorporate the main element’s ID in a dynamic subfolder path, you would use instead of just id. Combined with the above, this would mean owner.canonicalId.

If the rendered subfolder path ends up blank, contains a leading or trailing forward slash (e.g. foo/), or an empty segment (e.g. foo//bar), Craft will interpret that as a sign that a variable in the subfolder template couldn’t be resolved successfully, and the path will be considered invalid. If you are intentionally outputting a blank segment, output :ignore:. For example, if you want to output the first selected category, or nothing if there isn’t one, do this:

{{ ?? ':ignore:' }}

# The Field

Assets fields list all the currently-related assets, with a button to select new ones.

Choosing Add an asset will bring up a modal window where you can find and select additional assets, as well as upload new ones.

You can also upload assets by dragging files directly onto the assets field, or into the modal window.

# Inline Asset Editing

Double-click on a related asset to edit it in a slideout.

You can choose which custom fields should be available for assets in each volume from SettingsAssets[Volume Name]Field Layout.

# Development

# Querying Elements with Assets Fields

When querying for elements that have an Assets field, you can filter the results based on the Assets field data using a query param named after your field’s handle.

Possible values include:

Value Fetches elements…
':empty:' that don’t have any related assets.
':notempty:' that have at least one related asset.
100 that are related to the asset with an ID of 100.
[100, 200] that are related to an asset with an ID of 100 or 200.
[':empty:', 100, 200] with no related assets, or are related to an asset with an ID of 100 or 200.
['and', 100, 200] that are related to the assets with IDs of 100 and 200.
an Asset (opens new window) object that are related to the asset.
an AssetQuery (opens new window) object that are related to any of the resulting assets.
{# Fetch entries with a related asset #}
{% set entries = craft.entries()
  .all() %}

# Working with Assets Field Data

If you have an element with an Assets field in your template, you can access its related assets using your Assets field’s handle:

{% set query = entry.myFieldHandle %}

That will give you an asset query, prepped to output all the related assets for the given field.

To loop through all the related assets, call all() (opens new window) and then loop over the results:

{% set relatedAssets = entry.myFieldHandle.all() %}
{% if relatedAssets|length %}
    {% for rel in relatedAssets %}
      <li><a href="{{ rel.url }}">{{ rel.filename }}</a></li>
    {% endfor %}
{% endif %}

When using asset.url or asset.getUrl(), the asset’s source volume must have Assets in this volume have public URLs enabled and a Base URL setting. Otherwise, the result will always be empty.

If you only want the first related asset, call one() (opens new window) instead and make sure it returned something:

{% set rel = %}
{% if rel %}
  <p><a href="{{ rel.url }}">{{ rel.filename }}</a></p>
{% endif %}

If you need to check for related assets without fetching them, you can call exists() (opens new window):

{% if entry.myFieldHandle.exists() %}
  <p>There are related assets!</p>
{% endif %}

You can set parameters on the asset query as well. For example, to ensure that only images are returned, you can set the kind param:

{% set relatedAssets = entry.myFieldHandle
  .all() %}

In Craft 3, we recommended cloning these query objects using the clone keyword (opens new window) or clone() Twig function before applying params. This is no longer required in Craft 4, because a new copy of the query is returned each time you access the field property.

# Saving Assets Fields

If you have an element form, such as an entry form (opens new window), that needs to contain an Assets field, you will need to submit your field value as a list of asset IDs in the order you want them to be related.

For example, you could create a list of checkboxes for each of the possible relations:

{# Include a hidden input first so Craft knows to update the existing value
   if no checkboxes are checked. #}
{{ hiddenInput('fields[myFieldHandle]', '') }}

{# Get all of the possible asset options #}
{% set possibleAssets = craft.assets()
  .orderBy('filename ASC')
  .withTransforms([{ width: 100, height: 100 }])
  .all() %}

{# Get the currently related asset IDs #}
{% set relatedAssetIds = entry is defined
  ? entry.myFieldHandle.ids()
  : [] %}

  {% for possibleAsset in possibleAssets %}
        {{ input(
          { checked: in relatedAssetIds }
        ) }}
        {{ tag('img', { src: possibleAsset.url }) }}
        {{ possibleAsset.getImg({ width: 100, height: 100 }) }}
        {{ possibleAsset.filename }}
  {% endfor %}

You could then make the checkbox list sortable, so users have control over the order of related assets.

# Creating New Assets

Assets fields can handle new file uploads as well:

{{ input('file', 'fields[myFieldHandle][]', options={
  multiple: true,
}) }}

Don’t forget to set enctype="multipart/form-data" on your <form> tag so your browser knows to submit the form as a multipart request.

Alternatively, you can submit base64-encoded file data, which the Assets field will decode and treat as an uploaded file. To do that, you have to specify both the data and the filename like this:

{{ hiddenInput(
) }}
{{ hiddenInput('fields[myFieldHandle][filename][]', 'myFile.ext') }}

However you upload new assets, you may want to maintain any that already exist on the field and append new ones to the set instead of replacing it.

You can do this by passing each of the related asset IDs in the field data array, like we are here with hidden form inputs:


{# Provide each existing asset ID in the array of field data #}
{% for relatedAssetId in entry.myFieldHandle.ids() %}
  {{ input(
  ) }}
{% endfor %}

{{ input('file', 'fields[myFieldHandle][]', options={
  multiple: true,
}) }}

# See Also