oEmbed Template Elements

June 9, 2023

Drupal's default oEmbed template is extremely sparse, and some accessibility checkers don't like that.

The missing elements:

  1. A <title> tag.
  2. Language attributes on the <html> tag.

Fortunately these are pretty easy to deal with. The first step is to make the required information available to the Twig template via template_preprocess_media_oembed_iframe():

/**
 * Implements template_preprocess_media_oembed_iframe().
 *
 * Add a head title and language to oEmbed iframes.
 */
function THEME_preprocess_media_oembed_iframe(array &$variables) {
  if (!isset($variables['head_title']) || (!$variables['head_title'])) {
  	// Set a default better-than-nothing title.
    $placeholders = ['@site_name' => \Drupal::config('system.site')->get('name')];
    $variables['head_title'] = t('@site_name Media', $placeholders);
    // If a resource is available, and it has a title, use that instead.
    if (isset($variables['resource']) && ($resource_title = $variables['resource']->getTitle())) {
      $variables['head_title'] = $resource_title;
    }
  }
  if (!isset($variables['html_attributes'])) {
  	// Make language attributes available.
    $variables['html_attributes'] = new Attribute();
    if ($language = \Drupal::languageManager()->getCurrentLanguage()) {
      if ($lang = $language->getId()) {
        $variables['html_attributes']->setAttribute('lang', $lang);
      }
      if ($dir = $language->getDirection()) {
        $variables['html_attributes']->setAttribute('dir', $dir);
      }
    }
  }
}

Note that in order to create attributes the Attribute class has to be available at the top:

use Drupal\Core\Template\Attribute;

With that in place, it's just a matter of providing a media-oembed-iframe.html.twig Twig template that puts the elements in the right places:

<!DOCTYPE html>
<html{{ html_attributes }}>
  <head>
    <title>{{ head_title }}</title>
    <css-placeholder token="{{ placeholder_token }}">
  </head>
  <body style="margin: 0">
    {{ media|raw }}
  </body>
</html>

This is just the default template with the new elements added—ordinarily I'd go out of my way to remove the inline CSS, but in this case I'm not confident enough in my knowledge of all the contexts where this might appear to start messing around with that, so it gets to stay.

Joe Batt's Arm on Fogo Island, Newfoundland, August 2022

Joe Batt's Arm on Fogo Island, Newfoundland, August 2022