1 filter.module _filter_image_caption($text)

Implements callback_filter_process().

Replace img data-caption attributes with figure and figcaption elements.

Related topics


core/modules/filter/filter.module, line 2525
Framework for handling the filtering of content.


function _filter_image_caption($text) {
  // If no captions, immediately return.
  if (stristr($text, 'data-caption') === FALSE) {
    return $text;

  // Load the text as a DOM object for manipulation.
  $dom = filter_dom_load($text);
  $xpath = new DOMXPath($dom);

  foreach ($xpath->query('//*[@data-caption]') as $node) {
    // Read the data-caption attribute's value, then delete it.
    $caption = $node->getAttribute('data-caption');

    // Sanitize caption: decode HTML encoding, limit allowed HTML tags; only
    // allow inline tags that are allowed by default, plus <br>.
    $caption = filter_xss($caption, array('a', 'em', 'strong', 'cite', 'code', 'br'));

    // The caption must be non-empty.
    if (backdrop_strlen($caption) === 0) {

    // Given the updated node and caption: re-render it with a caption, but
    // bubble up the value of the class attribute of the captioned element,
    // this allows it to collaborate with e.g. the filter_align filter.
    $attributes = array();
    $tag = $node->tagName;
    $classes = $node->getAttribute('class');
    $node = ($node->parentNode->tagName === 'a') ? $node->parentNode : $node;
    if ($classes) {
      $attributes['class'] = explode(' ', $classes);
    $attributes['class'][] = 'caption';
    $attributes['class'][] = 'caption-' . $node->tagName;

    $theme_parameters = array(
      'item' => $node->ownerDocument->saveXML($node),
      'tag' => $tag,
      'caption' => $caption,
      'attributes' => $attributes,

    // In order to test this filter without a database connection, we
    // may directly call theme_filter_caption() to generate output.
    if (Database::isActiveConnection()) {
      $filter_caption = theme('filter_caption', $theme_parameters);
    else {
      module_load_include('inc', 'filter', 'filter.theme');
      $filter_caption = theme_filter_caption($theme_parameters);

    // Load the altered HTML into a new DOMDocument and retrieve the element.
    $updated_node = filter_dom_load($filter_caption)

    // Import the updated node from the new DOMDocument into the original
    // one, importing also the child nodes of the updated node.
    $updated_node = $dom->importNode($updated_node, TRUE);

    // Finally, replace the original node with the new node.
    $node->parentNode->replaceChild($updated_node, $node);

  return filter_dom_serialize($dom);