function FilterCaption::process

Same name and namespace in other branches
  1. 9 core/modules/filter/src/Plugin/Filter/FilterCaption.php \Drupal\filter\Plugin\Filter\FilterCaption::process()
  2. 10 core/modules/filter/src/Plugin/Filter/FilterCaption.php \Drupal\filter\Plugin\Filter\FilterCaption::process()
  3. 11.x core/modules/filter/src/Plugin/Filter/FilterCaption.php \Drupal\filter\Plugin\Filter\FilterCaption::process()

Overrides FilterInterface::process

File

core/modules/filter/src/Plugin/Filter/FilterCaption.php, line 66

Class

FilterCaption
Provides a filter to caption elements.

Namespace

Drupal\filter\Plugin\Filter

Code

public function process($text, $langcode) {
    $result = new FilterProcessResult($text);
    if (stristr($text, 'data-caption') !== FALSE) {
        $dom = Html::load($text);
        $xpath = new \DOMXPath($dom);
        $html_filter = $this->filterManager
            ->createInstance('filter_html', [
            'settings' => [
                'allowed_html' => '<a href hreflang target rel> <em> <strong> <cite> <code> <br>',
                'filter_html_help' => FALSE,
                'filter_html_nofollow' => FALSE,
            ],
        ]);
        foreach ($xpath->query('//*[@data-caption]') as $node) {
            // Read the data-caption attribute's value, then delete it.
            $caption = Html::escape($node->getAttribute('data-caption'));
            $node->removeAttribute('data-caption');
            // Sanitize caption: decode HTML encoding, limit allowed HTML tags; only
            // allow inline tags that are allowed by default, plus <br>.
            $caption = Html::decodeEntities($caption);
            $raw_caption = $caption;
            $filtered_caption = $html_filter->process($caption, $langcode);
            $result->addCacheableDependency($filtered_caption);
            $caption = FilteredMarkup::create($filtered_caption->getProcessedText());
            // The caption must be non-empty - however the Media Embed CKEditor
            // plugin uses a single space to represent a newly added caption. The
            // HTML filter will transform this into an empty string and prevent the
            // content editor from adding a new caption. To allow for this we treat
            // a raw caption value of ' ' as valid and adding the wrapping figure
            // element.
            // @see core/modules/media/js/plugins/drupalmedia/plugin.es6.js
            if (mb_strlen($caption) === 0 && $raw_caption !== ' ') {
                continue;
            }
            // 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.
            $tag = $node->tagName;
            $classes = $node->getAttribute('class');
            $node->removeAttribute('class');
            $node = $node->parentNode->tagName === 'a' ? $node->parentNode : $node;
            $filter_caption = [
                '#theme' => 'filter_caption',
                // We pass the unsanitized string because this is a text format
                // filter, and after filtering, we always assume the output is safe.
                // @see \Drupal\filter\Element\ProcessedText::preRenderText()
'#node' => FilteredMarkup::create($node->C14N()),
                '#tag' => $tag,
                '#caption' => $caption,
                '#classes' => $classes,
            ];
            $altered_html = \Drupal::service('renderer')->render($filter_caption);
            // Load the altered HTML into a new DOMDocument and retrieve the element.
            $updated_nodes = Html::load($altered_html)->getElementsByTagName('body')
                ->item(0)->childNodes;
            foreach ($updated_nodes as $updated_node) {
                // 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);
                $node->parentNode
                    ->insertBefore($updated_node, $node);
            }
            // Finally, remove the original data-caption node.
            $node->parentNode
                ->removeChild($node);
        }
        $result->setProcessedText(Html::serialize($dom))
            ->addAttachments([
            'library' => [
                'filter/caption',
            ],
        ]);
    }
    return $result;
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.