1

I have a node that has an entity reference field to a Media entity. That media entity has a field on it "caption". I want to render this caption directly in my twig template, so instead of doing this:

{{ content.field_media_item }}

Which would output the entire rendered media entity, I just want to output a field from that media entity. I've tried this:

{{ content.field_media_item[0]['#media'].field_caption.value }}

Which works, but since it's already rendered output, all the HTML from that value is escaped. So <p> tags appear as literal <p>. I could tack on a |raw at the end, which actually seems safe to me since I know the output has already been rendered and passed thru the field formatter, but seems wrong?

What's a better way of doing this? Using a pre-processor to access the field data from the reference media entity and passing it through a field formatter again or something? That actually seems inefficient since the caption field data was already rendered properly, and I'd be passing it thru the formatter again.

  • 1
    Instead of using the value, just let twig render the field (so remove the ".value" at the end). Then you can control the way the field is rendered in the Drupal backoffice >> media entity >> manage display. – Bogdan Feb 10 '17 at 15:34
  • |raw is definitely a security problem here, because #media is not a field formatter, this is an entity and you get the value directly from the database. – 4k4 Feb 10 '17 at 16:55
1

After some more thought and research, I think the best approach to this problem is to use a theme pre-processor function to manually prepare the entity reference field.

The main issue is that the referenced entity has a formatted text field that I need to output. That means it needs to run through the formatter before it's considered safe for output.

Manually accessing the value through the entity object in Twig is not a good solution because it will just print the raw value from the database, which twig will by default escape. Tacking on |raw makes it unsafe because it still hasn't run through the text processor.

Here's a preprocessor snippet that does what I need:

/**
 * Implements hook_preprocess_node().
 */
function MY_THEME_preprocess_node(array &$variables) {
  $node = $variables['node'];
  if ($node->bundle() == 'news') {
    // Extract the caption from the cover image media entity and prepare it manually. We do this because in our template, we render the caption separately from the image.
    if (!$node->field_news_cover_image->isEmpty()) {
      $image_media_entity = $node->field_news_cover_image->entity;
      $caption_field = $image_media_entity->field_media_caption;
      // Caption is formatted text, so we must output a render array that will
      // process the text with the appropriate filter.
      $variables['cover_photo_caption'] = [
        '#type' => 'processed_text',
        '#text' => $caption_field->value,
        '#format' => $caption_field->format,
        '#langcode' => $caption_field->getLangcode(),
      ];
    }
  }
}

This allows me to simply print {{ cover_photo_caption }} in the twig template.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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