class ConvertUrlToEmbedFilter in URL Embed 8
Provides a filter to display embedded entities based on data attributes.
Plugin annotation
@Filter(
id = "url_embed_convert_links",
title = @Translation("Convert URLs to URL embeds"),
description = @Translation("Convert plain URLs to embed elements that can be rendered with the <em>Display embedded URLs</em> filter."),
type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_REVERSIBLE,
settings = {
"url_prefix" = "",
},
)
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
- class \Drupal\filter\Plugin\FilterBase implements FilterInterface
- class \Drupal\url_embed\Plugin\Filter\ConvertUrlToEmbedFilter
- class \Drupal\filter\Plugin\FilterBase implements FilterInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
Expanded class hierarchy of ConvertUrlToEmbedFilter
File
- src/
Plugin/ Filter/ ConvertUrlToEmbedFilter.php, line 23
Namespace
Drupal\url_embed\Plugin\FilterView source
class ConvertUrlToEmbedFilter extends FilterBase {
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$form['url_prefix'] = [
'#type' => 'textfield',
'#title' => $this
->t('URL prefix'),
'#default_value' => $this->settings['url_prefix'],
'#description' => $this
->t('Optional prefix that will be used to indicate which URLs that apply. All URLs that are supported will be converted if empty. Example: EMBED-https://twitter.com/drupal/status/735873777683320832'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function process($text, $langcode) {
return new FilterProcessResult(static::convertUrls($text, $this->settings['url_prefix']));
}
/**
* Replaces appearances of supported URLs with <drupal-url> embed elements.
*
* Logic of this function is copied from _filter_url() and slightly adopted
* for our use case. _filter_url() is unfortunately not general enough to
* re-use it.
*
* @param string $text
* Text to be processed.
* @param string $url_prefix
* (Optional) Prefix that should be used to manually choose which URLs
* should be converted.
*
* @return string
* Processed text.
*/
public static function convertUrls($text, $url_prefix = '') {
// Tags to skip and not recurse into.
$ignore_tags = 'a|script|style|code|pre';
// Create an array which contains the regexps for each type of link.
// The key to the regexp is the name of a function that is used as
// callback function to process matches of the regexp. The callback function
// is to return the replacement for the match. The array is used and
// matching/replacement done below inside some loops.
$tasks = [];
// Prepare protocols pattern for absolute URLs.
// \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() will replace
// any bad protocols with HTTP, so we need to support the identical list.
// While '//' is technically optional for MAILTO only, we cannot cleanly
// differ between protocols here without hard-coding MAILTO, so '//' is
// optional for all protocols.
// @see \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols()
$protocols = \Drupal::getContainer()
->getParameter('filter_protocols');
$protocols = implode(':(?://)?|', $protocols) . ':(?://)?';
$valid_url_path_characters = "[\\p{L}\\p{M}\\p{N}!\\*\\';:=\\+,\\.\$\\/%#\\[\\]\\-_~@&]";
// Allow URL paths to contain balanced parens
// 1. Used in Wikipedia URLs like /Primer_(film)
// 2. Used in IIS sessions like /S(dfd346)/
$valid_url_balanced_parens = '\\(' . $valid_url_path_characters . '+\\)';
// Valid end-of-path characters (so /foo. does not gobble the period).
// 1. Allow =&# for empty URL parameters and other URL-join artifacts
$valid_url_ending_characters = '[\\p{L}\\p{M}\\p{N}:_+~#=/]|(?:' . $valid_url_balanced_parens . ')';
$valid_url_query_chars = '[a-zA-Z0-9!?\\*\'@\\(\\);:&=\\+\\$\\/%#\\[\\]\\-_\\.,~|]';
$valid_url_query_ending_chars = '[a-zA-Z0-9_&=#\\/]';
//full path
//and allow @ in a url, but only in the middle. Catch things like http://example.com/@user/
$valid_url_path = '(?:(?:' . $valid_url_path_characters . '*(?:' . $valid_url_balanced_parens . $valid_url_path_characters . '*)*' . $valid_url_ending_characters . ')|(?:@' . $valid_url_path_characters . '+\\/))';
// Prepare domain name pattern.
// The ICANN seems to be on track towards accepting more diverse top level
// domains, so this pattern has been "future-proofed" to allow for TLDs
// of length 2-64.
$domain = '(?:[\\p{L}\\p{M}\\p{N}._+-]+\\.)?[\\p{L}\\p{M}]{2,64}\\b';
$ip = '(?:[0-9]{1,3}\\.){3}[0-9]{1,3}';
$auth = '[\\p{L}\\p{M}\\p{N}:%_+*~#?&=.,/;-]+@';
$trail = '(' . $valid_url_path . '*)?(\\?' . $valid_url_query_chars . '*' . $valid_url_query_ending_chars . ')?';
// Match absolute URLs.
$url_pattern = "(?:{$auth})?(?:{$domain}|{$ip})/?(?:{$trail})?";
$pattern = "`{$url_prefix}((?:{$protocols})(?:{$url_pattern}))`u";
$tasks['replaceFullLinks'] = $pattern;
// HTML comments need to be handled separately, as they may contain HTML
// markup, especially a '>'. Therefore, remove all comment contents and add
// them back later.
_filter_url_escape_comments('', TRUE);
$text = preg_replace_callback('`<!--(.*?)-->`s', '_filter_url_escape_comments', $text);
// Split at all tags; ensures that no tags or attributes are processed.
$chunks = preg_split('/(<.+?>)/is', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
// PHP ensures that the array consists of alternating delimiters and
// literals, and begins and ends with a literal (inserting NULL as
// required). Therefore, the first chunk is always text:
$chunk_type = 'text';
// If a tag of $ignore_tags is found, it is stored in $open_tag and only
// removed when the closing tag is found. Until the closing tag is found,
// no replacements are made.
$open_tag = '';
for ($i = 0; $i < count($chunks); $i++) {
if ($chunk_type == 'text') {
// Only process this text if there are no unclosed $ignore_tags.
if ($open_tag == '') {
// If there is a match, inject a link into this chunk via the callback
// function contained in $task.
$chunks[$i] = preg_replace_callback($pattern, function ($match) {
if (\Drupal::service('url_embed')
->getEmbed(Html::decodeEntities($match[1]))) {
return '<drupal-url data-embed-url="' . $match[1] . '"></drupal-url>';
}
else {
return $match[1];
}
}, $chunks[$i]);
}
// Text chunk is done, so next chunk must be a tag.
$chunk_type = 'tag';
}
else {
// Only process this tag if there are no unclosed $ignore_tags.
if ($open_tag == '') {
// Check whether this tag is contained in $ignore_tags.
if (preg_match("`<({$ignore_tags})(?:\\s|>)`i", $chunks[$i], $matches)) {
$open_tag = $matches[1];
}
}
else {
if (preg_match("`<\\/{$open_tag}>`i", $chunks[$i], $matches)) {
$open_tag = '';
}
}
// Tag chunk is done, so next chunk must be text.
$chunk_type = 'text';
}
}
$text = implode($chunks);
// Revert to the original comment contents
_filter_url_escape_comments('', FALSE);
return preg_replace_callback('`<!--(.*?)-->`', '_filter_url_escape_comments', $text);
}
/**
* {@inheritdoc}
*/
public function tips($long = FALSE) {
if ($long) {
return $this
->t('<p>You can convert plain URLs to <drupal-url> HTML elements. Those elements are later converted to embeds using "Display embedded URLs" text filter.</p>');
}
else {
return $this
->t('You can convert plain URLs to embed elements.');
}
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
ConvertUrlToEmbedFilter:: |
public static | function | Replaces appearances of supported URLs with <drupal-url> embed elements. | |
ConvertUrlToEmbedFilter:: |
public | function |
Performs the filter processing. Overrides FilterInterface:: |
|
ConvertUrlToEmbedFilter:: |
public | function |
Generates a filter's settings form. Overrides FilterBase:: |
|
ConvertUrlToEmbedFilter:: |
public | function |
Generates a filter's tip. Overrides FilterBase:: |
|
DependencySerializationTrait:: |
protected | property | An array of entity type IDs keyed by the property name of their storages. | |
DependencySerializationTrait:: |
protected | property | An array of service IDs keyed by property name used for serialization. | |
DependencySerializationTrait:: |
public | function | 1 | |
DependencySerializationTrait:: |
public | function | 2 | |
FilterBase:: |
public | property | The name of the provider that owns this filter. | |
FilterBase:: |
public | property | An associative array containing the configured settings of this filter. | |
FilterBase:: |
public | property | A Boolean indicating whether this filter is enabled. | |
FilterBase:: |
public | property | The weight of this filter compared to others in a filter collection. | |
FilterBase:: |
public | function |
Calculates dependencies for the configured plugin. Overrides DependentPluginInterface:: |
1 |
FilterBase:: |
public | function |
Gets default configuration for this plugin. Overrides ConfigurableInterface:: |
|
FilterBase:: |
public | function |
Gets this plugin's configuration. Overrides ConfigurableInterface:: |
|
FilterBase:: |
public | function |
Returns the administrative description for this filter plugin. Overrides FilterInterface:: |
|
FilterBase:: |
public | function |
Returns HTML allowed by this filter's configuration. Overrides FilterInterface:: |
4 |
FilterBase:: |
public | function |
Returns the administrative label for this filter plugin. Overrides FilterInterface:: |
|
FilterBase:: |
public | function |
Returns the processing type of this filter plugin. Overrides FilterInterface:: |
|
FilterBase:: |
public | function |
Prepares the text for processing. Overrides FilterInterface:: |
|
FilterBase:: |
public | function |
Sets the configuration for this plugin instance. Overrides ConfigurableInterface:: |
1 |
FilterBase:: |
public | function |
Constructs a \Drupal\Component\Plugin\PluginBase object. Overrides PluginBase:: |
4 |
FilterInterface:: |
constant | HTML tag and attribute restricting filters to prevent XSS attacks. | ||
FilterInterface:: |
constant | Non-HTML markup language filters that generate HTML. | ||
FilterInterface:: |
constant | Irreversible transformation filters. | ||
FilterInterface:: |
constant | Reversible transformation filters. | ||
MessengerTrait:: |
protected | property | The messenger. | 29 |
MessengerTrait:: |
public | function | Gets the messenger. | 29 |
MessengerTrait:: |
public | function | Sets the messenger. | |
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the definition of the plugin implementation. Overrides PluginInspectionInterface:: |
3 |
PluginBase:: |
public | function |
Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface:: |
|
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |