Featured Images with Captions for News in Drupal 8

Or, getting fields into other field templates, and showing form fields and displayed fields conditionally.

The Image Caption field only shows up when I add an image.

We have a News content type. We want users to be able to feature an image, and add an optional caption. The image and caption should use the <figure> semantic HTML elements. The caption form field should only show up once a user has added a featured image. The caption should only be displayed on the published News article when there is a featured image and a caption filled in.

This is part of the same project where we created alternate urls for the News article title, which uses a similar technique:

https://medium.com/@sarahcodes/alternate-urls-for-news-titles-in-drupal-8-afc83b43cfd3

So there are two main steps beyond the default Drupal 8 functionality.

  1. Show or hide one form field (caption) based on the status of another form field (image).

Set-Up

Our news content type has an image field called Featured Image field_news_image . After it, we display a Text(plain) field called Caption field_news_caption. Both only allow 1 value.

Manage Form Display — place the caption form field where you want it to appear in the form.

Manage Display — place the caption field in Disabled. We’ll use the Image’s template to show the caption.

The Image Caption can be stowed away under Disabled in Manage Display

We used a combination of a custom module news and our theme to get this done. We did Part 1 in our module, and Part 2 in our theme.

  • If you want to do this entirely in theme — Part 1 can go in the .theme file, and the template in Part 2 in the templatesfolder.

Part 1: Showing/hiding form fields conditionally

I learned how to do this from this great post by Tahir Mushtaq: Drupal 8 — Conditionally hide a form field from February 2, 2017. It’s an excellent walk-through. Since my use-case is different from theirs I’ll summarize the steps I took, but please do read that article if you can.

Patch core. Per this bug report to Drupal 8 core, a patch is needed for the following code snippet to actually work. Thanks to my colleague Angela McMahon for tracking this down for us.

Bug report Display Bug when using #states (Forms API) with Ajax Request
Patch from January 15, 2018 by kfritsche.

Remember, apply un-approved core patches at your own risk and test carefully on your own projects.

Next, here is the code snippet I added to our news.module file:

/**
* Implements hook_form_alter().
*/
function news_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
if ($form_id == 'node_news_form' || $form_id == 'node_news_edit_form') {
$form['field_news_caption']['#states'] = [
'visible' => [
':input[name="files[field_news_image_0]"]' => ['filled' => TRUE],
],
];
}
}

Without the patch, this sorta works, but eh? The caption field doesn’t know that the image field is ‘filled’ until you save. Not terrible, but not great user experience at all. So, we patched.

  • news_form_alter — news is the name of my module.
The Image Caption field only shows up when I add an image.

Part 2: Display the image and caption as a <figure>

Look, I added a copyright to my digital painting as a caption.

This is the desired HTML:

<figure>
<img src="myimage.png" alt="its a placeholder okay">
<figcaption>This is my very good picture.<figcaption>
</figure>

About figures and figcaptions: https://www.w3.org/TR/html5/grouping-content.html#the-figure-element

The strategy: modify the template for the Featured Image field to a) look for the caption field, and b) modify the html to use <figure>.

Code first, then explanation.

File name: field--node--field-news-image.html.twig

{% for item in items %}
{% if element['#object'].field_news_caption.0 %}
<figure class="mb-3 figure">
{{ item.content }}
<figcaption class="figure-caption">{{ element['#object'].field_news_caption.value }}</figcaption>
</figure>
{% else %}
<div class="mb-3">
{{ item.content }}
</div>
{% endif %}
{% endfor %}
  • This template overrides the regular field.html.twig. I used Twig debugging to find the right name for my template.

Note: It can be tricky to figure out how to get specific pieces of different field types to use in Twig templates. I am working on a guide:

That’s it, that’s all

It is usually my preference to keep all display concerns as far forward in the UI as I can, but this case, for me, was easier and simpler to handle with a tiny little Twig template.

I’m a little bit in love with this technique because it feels so simple and tidy, and makes a content type more flexible. Hope this helps.

I’m a front-end developer and web designer and love to code a lot.