8

Apologies if this question has already been asked. However, in my research I found the answers have been for simple image fields which are in default install of Drupal 8. However, in order to have reusable media, I am using Media Entity and associated modules. The problem is I am not able to access image or its URL in TWIG template, where simple image fields work just fine.

While the code below works as expected if field_image is a simple Image type, but doesn't work if it is Entity Reference field.

<div class="header-title white overlay" style="background-image:url({{content.field_image.0}});">

In case of Entity Reference field, the output is fully escaped and breaks the structure of my theme. How can I get raw image or URL? I am not a programmer so I don't know how to write preprocessor code.

I am attaching configuration images for the Media Bundle I am using and the node configuration in which I'm using the two types of image fields.

Media Bundle configuration enter image description here

Node configuration. Note, 'field_image' is default drupal image type, while 'field_image2' is an entity reference field as configured in the Media bundle above. enter image description here

Please advice how to get this working. Thanks.

Drupal Configuration

  • Drupal 8.3
  • media_entity_browser-8.x-1.0-beta2
  • media_entity-8.x-1.6
  • media_entity_image-8.x-1.2
  • embed-8.x-1.0-rc3
  • entity-8.x-1.0-beta2
  • inline_entity_form-8.x-1.0-beta1
  • file_entity-8.x-2.0-beta3
  • file-8.2.6
  • field_formatter-8.x-1.0
  • image_raw_formatter-8.x-1.x-dev
  • image_url_formatter-image_url_formatter

1 Answer 1

8

If this entity referenced image is controlled by Media, then you should let normal rendering occur:

{{ content.field_image2 }}

The rendering is then controlled by the field formatter, which will look to a display mode in Media, which is not dissimilar from Node display modes (default, teaser, etc).

Your filename would be something like:

media--media-bundle--display-mode.html.twig
media--media-bundle.html.twig

The first one is most specific, the second one would be the base for that media entity wherever it is used. I usually opt for the first one.

It is in this specific twig template where that code should live. The markup should be sourced there, instead of the referencing entity, in my opinion.

You could also do some preprocessing to solve this as well. Here is an example:

/**
 * Implements hook_preprocess_node().
 * @param $variables
 */
function mytheme_preprocess_node(&$variables) {
  $node = $variables['elements']['#node'];
  $bundle = $node->bundle();

  if ($bundle == 'landing_page' && $variables['elements']['#view_mode'] == 'hero') {
    $hero_image = $node->get('field_hero_image')->getValue();

    if (!empty($hero_image)) {
      $entity = Media::load($hero_image[0]['target_id']);
      $variables['hero_image'] = ImageStyle::load('landing_page_hero')->buildUrl($entity->field_image->entity->getFileUri());
    }
  }
}

Then in my respective template...

<div{{ attributes.addClass(classes) }} style="background-image: url('{{ hero_image }}');"></div>

Alternatively, you can preprocess the media entity:

/**
 * Prepares variables for media templates.
 *
 * Default template: media.html.twig.
 *
 * @param array $variables
 *   An associative array containing:
 *   - media: An individual media for display.
 */
function mytheme_preprocess_media(&$variables) {
  /** @var \Drupal\media_entity\MediaInterface $media */
  $media = $variables['elements']['#media'];

  $variables['media'] = $media;
  $variables['name'] = $media->label();

  // Helpful $content variable for templates.
  foreach (Element::children($variables['elements']) as $key) {
    $variables['content'][$key] = $variables['elements'][$key];
  }

  $variables['attributes']['class'][] = 'media';
  $variables['attributes']['class'][] = Html::getClass('media-' . $media->bundle());

  if (!$media->isPublished()) {
    $variables['attributes']['class'][] = 'unpublished';
  }

  if ($variables['elements']['#view_mode']) {
    $variables['attributes']['class'][] = Html::getClass('view-mode-' . $variables['elements']['#view_mode']);

    if ($variables['elements']['#view_mode'] == 'hero') {
      $variables['hero_image'] = ImageStyle::load('hero')->buildUrl($media->field_image->entity->getFileUri());
    }
  }
}
13
  • Thank you for taking time to answering. However, I got the following error when I tried the first code sample (with appropriate changes of course): Error: Class 'Drupal\media\Media' not found in saha_preprocess_node() I'm just trying to get a simple URL to the image, the problem is it always shows the image URL escaped in "" marks and withing the <article> tag. Is there any way I can get a simple image url? Where do I find the structure of the render array used by the Media / Media Image module?
    – Vikram
    Feb 26, 2017 at 13:58
  • You have to add the use statement at the top of the file to include the Media class, then this error will go away. use Drupal\media\Media
    – Kevin
    Feb 26, 2017 at 15:09
  • The above code also shows how to obtain the file uri.
    – Kevin
    Feb 26, 2017 at 15:14
  • Already tried that. I get the following error: Error: Class 'Drupal\media\Media' not found in saha_preprocess_node()
    – Vikram
    Feb 26, 2017 at 18:55
  • 3
    for media_entity I used $entity = \Drupal::entityTypeManager()->getStorage("media")->load($hero_image[0]['target_id']);
    – GiorgosK
    Mar 2, 2017 at 16:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.