Dot All Lisbon – the official Craft CMS conference – is happening September 23 - 25.

Multi-select Fields

Multi-select fields give you an input where multiple items may be selected.

Screenshot of the multi-select field interface in the Craft control panel

Settings

url="https://my-craft-project.ddev.site/admin/settings/fields/new" :link="false" :max-height="500" caption="Adding a new multi-select field via the control panel.">

Multi-select fields have the following settings:

  • Multi-select Options – Define any number of options to populate the menu.
    • Optgroup? — Converts this option into a non-selectable “heading” to group other options.
    • Label — A text description of the option, displayed to the author.
    • Value — The value stored when a given option is selected.
    • Icon (Optional) — Choose from the standard system icon palette.
    • Color (Optional) — A color for the icon, or, when no icon is selected, a color pip.
    • Default? — One option can be marked as the default.

Development

The order in which options are selected is not preserved, and . If you wish to order the selections, consider using one of the relational fields.

Working with Multi-select Field Data

If you have an element with a multi-select field in your template, you can access its data using your multi-select field’s handle:

{% set value = entry.myFieldHandle %}
$value = $entry->myFieldHandle;

That will give you a craft5:craft\fields\data\MultiOptionsFieldData object that contains the selected options’ labels and values. You can use this like an array:

{% for option in entry.myFieldHandle %}
  Label: {{ option.label }}
  Value: {{ option }} or {{ option.value }}
{% endfor %}
foreach ($entry->myFieldHandle as $option) {
    // Label: $option->label
    // Value: (string)$option or $option->value
}

To loop through all the available options, iterate over the options property:

{% for option in entry.myFieldHandle.options %}
  Label:    {{ option.label }}
  Value:    {{ option }} or {{ option.value }}
  Selected: {{ option.selected ? 'Yes' : 'No' }}
{% endfor %}
foreach ($entry->myFieldHandle->options as $option) {
    // Label:    $option->label
    // Value:    (string)$option or $option->value
    // Selected: $option->selected
}

To see if any options are selected, use the length filter (or PHP’s count() function):

{% if entry.myFieldHandle|length %}
  {# At least one option was selected! #}
{% endif %}
if (count($entry->myFieldHandle)) {
    // At least one option was selected!
}

To see if a particular option is selected, use contains():

{% if entry.myFieldHandle.contains('foo') %}
  {# `foo` is among the selected options! #}
{% endif %}
if ($entry->myFieldHandle->contains('foo')) {
    // `foo` is among the selected options!
}

Querying Elements with Multi-select Fields

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

Possible values include:

| Value | Fetches elements… | - | - | 'foo' | with a foo option selected. | 'not foo' | without a foo option selected. | ['foo', 'bar'] | with foo or bar options selected. | ['and', 'foo', 'bar'] | with foo and bar options selected.

{# Fetch entries with the 'foo' option selected #}
{% set entries = craft.entries()
  .myFieldHandle('foo')
  .all() %}
// Fetch entries with the 'foo' option selected
$entries = \craft\elements\Entry::find()
    ->myFieldHandle('foo')
    ->all();

Saving Multi-select Fields

If you have a front-end element form (such as an entry form) that incorporates multi-select field data, you can use this template as a starting point:

{# Fetch the global field definition: #}
{% set field = craft.app.fields.getFieldByHandle('myFieldHandle') %}

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

  {% for option in field.options %}
    {% set selected = entry is defined
      ? entry.myFieldHandle.contains(option.value)
      : option.default %}

    {{ tag('option', {
      value: option.value,
      text: option.label,
      selected: selected,
    })}}
  {% endfor %}