fivejars / media_directories_element
Provides the media_directories form element: the Media Directories browser widget for custom forms.
Package info
github.com/fivejars/media_directories_element
Type:drupal-module
pkg:composer/fivejars/media_directories_element
Requires
- php: >=8.3
- drupal/core: ^11
- drupal/media_directories: ^3.0
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Provides the media_directories form element: the
Media Directories browser
widget for custom forms that have no field to attach a widget to (Layout
Builder section settings, block and plugin configuration forms, settings
forms).
The element renders the same markup as the
media_directories_browser_widget field widget, so it looks and behaves the
same: an "Add media" button opening the browser modal, sortable preview tiles
with Edit / Remove, and a cardinality hint.
It is a drop-in replacement for the media_library element of
Media Library Form API Element:
it accepts the same #default_value formats and returns the same submitted
value, so switching only needs a new #type.
Requirements
- Drupal 11
- Media Directories, with its
media_directories_browsersubmodule
Installation
Media Directories has no stable release yet, and Composer ignores stability
flags of dependencies, so a site with minimum-stability: stable requires it
explicitly first:
composer require drupal/media_directories:^3.0@RC composer require fivejars/media_directories_element drush en media_directories_element
Usage
$form['image'] = [ '#type' => 'media_directories', '#title' => $this->t('Image'), '#default_value' => $media_id, '#cardinality' => 1, '#allowed_bundles' => ['image'], ];
On submit (including programmatic submissions with any #default_value
format), the value is a comma-separated string of media IDs ('42',
'1,2,3'), or '' when nothing is selected:
$ids = array_filter(explode(',', $form_state->getValue('image')));
Properties
| Property | Default | Description |
|---|---|---|
#default_value |
NULL |
Pre-selected media: NULL, an ID (42), a comma-separated string ('1,2,3') or an array of IDs ([1, 2, 3]). |
#cardinality |
1 |
Maximum number of items, a positive integer; -1 for unlimited. Anything else falls back to 1. |
#allowed_bundles |
[] |
Allowed media type machine names; empty for all. |
#button_label |
'Add media' |
Label of the button opening the browser. |
#collapsible |
FALSE |
Render a <details> instead of a <fieldset>. |
#collapsed |
FALSE |
Start a collapsible element collapsed. |
#open_when_empty |
FALSE |
Keep a collapsed element open while no media is selected. |
#title, #description, #required and #states work as on any form
element.
Validation
The value is checked server side, so a tampered or stale value can't pick media the user may not:
- Deleted media drops out.
- Newly picked media of a bundle not in
#allowed_bundles, or that the current user may not view, drops out. - Media already saved in
#default_valuethat the user may not pick (e.g. unpublished, or of a bundle no longer allowed) is kept, shown as an "Unavailable media" tile the user can remove. Re-saving a form never drops it silently. - More than
#cardinalityitems is a validation error.
Off-canvas forms
The widget opens a tile's "Edit" form in the off-canvas dialog. When the element is itself rendered in off-canvas (e.g. Layout Builder), that would replace the form being edited, so there the Edit form opens in a modal dialog instead, and saving it closes only the modal.
Tests
vendor/bin/phpunit -c web/core web/modules/contrib/media_directories_element/tests
MediaDirectoriesTest covers the element itself. ParentContractTest checks
what the element reuses from media_directories_browser (widget JS selectors,
library, preview template variables, quick edit route, media service): run it
after updating Media Directories, and a failure names what changed.
Migrating from media_library_form_element
Replace '#type' => 'media_library' with '#type' => 'media_directories'.
#allowed_bundles, #cardinality and #default_value keep their meaning, and
the submitted value has the same format.