class FilterCaption
Same name in other branches
- 8.9.x core/modules/filter/src/Plugin/Filter/FilterCaption.php \Drupal\filter\Plugin\Filter\FilterCaption
- 10 core/modules/filter/src/Plugin/Filter/FilterCaption.php \Drupal\filter\Plugin\Filter\FilterCaption
- 11.x core/modules/filter/src/Plugin/Filter/FilterCaption.php \Drupal\filter\Plugin\Filter\FilterCaption
Provides a filter to caption elements.
When used in combination with the filter_align filter, this must run last.
Plugin annotation
@Filter(
id = "filter_caption",
title = @Translation("Caption images"),
description = @Translation("Uses a <code>data-caption</code> attribute on <code><img></code> tags to caption images."),
type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_REVERSIBLE
)
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements \Drupal\Component\Plugin\PluginInspectionInterface, \Drupal\Component\Plugin\DerivativeInspectionInterface
- class \Drupal\Core\Plugin\PluginBase extends \Drupal\Component\Plugin\PluginBase uses \Drupal\Core\StringTranslation\StringTranslationTrait, \Drupal\Core\DependencyInjection\DependencySerializationTrait, \Drupal\Core\Messenger\MessengerTrait
- class \Drupal\filter\Plugin\FilterBase extends \Drupal\Core\Plugin\PluginBase implements \Drupal\filter\Plugin\FilterInterface
- class \Drupal\filter\Plugin\Filter\FilterCaption extends \Drupal\filter\Plugin\FilterBase implements \Drupal\Core\Plugin\ContainerFactoryPluginInterface
- class \Drupal\filter\Plugin\FilterBase extends \Drupal\Core\Plugin\PluginBase implements \Drupal\filter\Plugin\FilterInterface
- class \Drupal\Core\Plugin\PluginBase extends \Drupal\Component\Plugin\PluginBase uses \Drupal\Core\StringTranslation\StringTranslationTrait, \Drupal\Core\DependencyInjection\DependencySerializationTrait, \Drupal\Core\Messenger\MessengerTrait
Expanded class hierarchy of FilterCaption
File
-
core/
modules/ filter/ src/ Plugin/ Filter/ FilterCaption.php, line 25
Namespace
Drupal\filter\Plugin\FilterView source
class FilterCaption extends FilterBase implements ContainerFactoryPluginInterface {
/**
* Filter manager.
*
* @var \Drupal\filter\FilterPluginManager
*/
protected $filterManager;
/**
* Constructs a new FilterCaption.
*
* @param array $configuration
* Configuration.
* @param string $plugin_id
* Plugin ID.
* @param mixed $plugin_definition
* Definition.
* @param \Drupal\filter\FilterPluginManager $filter_manager
* Filter plugin manager.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, FilterPluginManager $filter_manager = NULL) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->filterManager = $filter_manager ?: \Drupal::service('plugin.manager.filter');
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container->get('plugin.manager.filter'));
}
/**
* {@inheritdoc}
*/
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;
}
/**
* {@inheritdoc}
*/
public function tips($long = FALSE) {
if ($long) {
return $this->t('
<p>You can caption images, videos, blockquotes, and so on. Examples:</p>
<ul>
<li><code><img src="" data-caption="This is a caption" /></code></li>
<li><code><video src="" data-caption="The Drupal Dance" /></code></li>
<li><code><blockquote data-caption="Dries Buytaert">Drupal is awesome!</blockquote></code></li>
<li><code><code data-caption="Hello world in JavaScript.">alert("Hello world!");</code></code></li>
</ul>');
}
else {
return $this->t('You can caption images (<code>data-caption="Text"</code>), but also videos, blockquotes, and so on.');
}
}
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overriden Title | Overrides |
---|---|---|---|---|---|
FilterBase::$provider | public | property | The name of the provider that owns this filter. | ||
FilterBase::$settings | public | property | An associative array containing the configured settings of this filter. | ||
FilterBase::$status | public | property | A Boolean indicating whether this filter is enabled. | ||
FilterBase::$weight | public | property | The weight of this filter compared to others in a filter collection. | ||
FilterBase::calculateDependencies | public | function | Calculates dependencies for the configured plugin. | Overrides DependentPluginInterface::calculateDependencies | 1 |
FilterBase::defaultConfiguration | public | function | Gets default configuration for this plugin. | Overrides ConfigurableInterface::defaultConfiguration | |
FilterBase::getConfiguration | public | function | Gets this plugin's configuration. | Overrides ConfigurableInterface::getConfiguration | |
FilterBase::getDescription | public | function | Returns the administrative description for this filter plugin. | Overrides FilterInterface::getDescription | |
FilterBase::getHTMLRestrictions | public | function | Returns HTML allowed by this filter's configuration. | Overrides FilterInterface::getHTMLRestrictions | 4 |
FilterBase::getLabel | public | function | Returns the administrative label for this filter plugin. | Overrides FilterInterface::getLabel | |
FilterBase::getType | public | function | Returns the processing type of this filter plugin. | Overrides FilterInterface::getType | |
FilterBase::prepare | public | function | Prepares the text for processing. | Overrides FilterInterface::prepare | |
FilterBase::setConfiguration | public | function | Sets the configuration for this plugin instance. | Overrides ConfigurableInterface::setConfiguration | 1 |
FilterBase::settingsForm | public | function | Generates a filter's settings form. | Overrides FilterInterface::settingsForm | 3 |
FilterCaption::$filterManager | protected | property | Filter manager. | ||
FilterCaption::create | public static | function | Creates an instance of the plugin. | Overrides ContainerFactoryPluginInterface::create | |
FilterCaption::process | public | function | Performs the filter processing. | Overrides FilterInterface::process | |
FilterCaption::tips | public | function | Generates a filter's tip. | Overrides FilterBase::tips | |
FilterCaption::__construct | public | function | Constructs a new FilterCaption. | Overrides FilterBase::__construct | |
FilterInterface::TYPE_HTML_RESTRICTOR | constant | HTML tag and attribute restricting filters to prevent XSS attacks. | |||
FilterInterface::TYPE_MARKUP_LANGUAGE | constant | Non-HTML markup language filters that generate HTML. | |||
FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE | constant | Irreversible transformation filters. | |||
FilterInterface::TYPE_TRANSFORM_REVERSIBLE | constant | Reversible transformation filters. | |||
PluginInspectionInterface::getPluginDefinition | public | function | Gets the definition of the plugin implementation. | 6 | |
PluginInspectionInterface::getPluginId | public | function | Gets the plugin_id of the plugin instance. | 2 |
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.