Jump to content

ICT:Drupal opener explained

From Costa Sano MediaWiki
Revision as of 09:53, 12 March 2026 by Mngr (talk | contribs)

Custom Media Library Opener for Heritage Digital Assets

In Drupal 11.3.5, a custom "Opener" service allows the Media Library to be used as a standalone modal. This implementation restricts selection to one and only one asset and returns a rendered thumbnail to the parent page, mimicking the "classical" Media Library behavior without the full Field API overhead.

1. Define the Service

Register the opener in your module's your_module.services.yml. You must tag it with media_library.opener so the system can identify it.

services:
  your_module.heritage_opener:
    class: Drupal\your_module\HeritageAssetOpener
    arguments: ['@entity_type.manager']
    tags:
      - { name: media_library.opener }

2. The Opener Logic

Create src/HeritageAssetOpener.php. This class handles the permission check and generates the AJAX response to inject the thumbnail.

namespace Drupal\your_module;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\media\Entity\Media;
use Drupal\media_library\MediaLibraryOpenerInterface;
use Drupal\media_library\MediaLibraryState;

class HeritageAssetOpener implements MediaLibraryOpenerInterface {

  protected $entityTypeManager;

  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * Checks if the user can access the media library in this context.
   */
  public function checkAccess(MediaLibraryState $state, AccountInterface $account) {
    return AccessResult::allowedIfHasPermission($account, 'view media');
  }

  /**
   * Logic executed after clicking "Insert" in the modal.
   */
  public function getSelectionResponse(MediaLibraryState $state, array $selected_ids) {
    $selected_id = reset($selected_ids); // Force single selection logic
    $media = Media::load($selected_id);
    
    $response = new AjaxResponse();

    if ($media) {
      // Build the thumbnail using the 'media_library' view mode
      $view_builder = $this->entityTypeManager->getViewBuilder('media');
      $render_array = $view_builder->view($media, 'media_library');
      
      // Inject the thumbnail into the UI
      $response->addCommand(new HtmlCommand('#asset-preview-container', $render_array));
      
      // Update a hidden field with the ID for form submission
      $response->addCommand(new InvokeCommand('#selected-asset-id', 'val', [$selected_id]));
    }

    return $response;
  }
}

3. Triggering the Modal

To launch the modal from a controller or form, build a link using the MediaLibraryState. Setting media_library_remaining to 1 enforces the single-item limit.

use Drupal\Core\Url;
use Drupal\media_library\MediaLibraryState;

// Create the state for our custom opener
$state = MediaLibraryState::create(
  'your_module.heritage_opener', // Our service ID
  ['image', 'document'],         // Allowed types
  'image',                       // Default tab
  1                              // Quantity limit (1 for single asset)
);

$build['select_button'] = [
  '#type' => 'link',
  '#title' => $this->t('Select Heritage Asset'),
  '#url' => Url::fromRoute('media_library.ui', [], ['query' => $state->all()]),
  '#attributes' => [
    'class' => ['use-ajax', 'button'],
    'data-dialog-type' => 'modal',
    'data-dialog-options' => json_encode(['width' => '80%']),
  ],
  '#attached' => ['library' => ['core/drupal.dialog.ajax']],
];

4. Required HTML Placeholders

Ensure your template or form contains these matching IDs:

  • id="asset-preview-container": Where the thumbnail will appear.
  • id="selected-asset-id": A hidden input to store the ID for the backend.

Configuration: Custom View Mode

To ensure the selected heritage asset matches the project's design, we use a dedicated view mode instead of the generic library thumbnail.

1. UI Configuration Steps

  1. Go to Structure > Display modes > View modes and add a new "Media" mode named Template:code.
  2. Navigate to Structure > Media types > [Your Type] > Manage display.
  3. Enable the Template:code under Custom display settings.
  4. Configure the layout:
    • Hide all fields except the main file/image.
    • Set the Format to Thumbnail and select a custom Image Style (e.g., Template:code).

2. Code Implementation

Update the Template:code method in Template:code to call this specific mode:

// Render the media using our project-specific view mode
$render_array = $view_builder->view($media, 'heritage_asset_preview');

3. CSS Styling

You can now target this specific preview in your theme:

.heritage-thumbnail-wrapper [data-drupal-view-mode="heritage_asset_preview"] {
  border: 2px solid #a39161; /* Heritage gold border */
  box-shadow: 3px 3px 10px rgba(0,0,0,0.2);
  max-width: 300px;
}