entity_embed.module in Entity Embed 8
Same filename and directory in other branches
Framework for allowing entities to be embedded in CKEditor.
File
entity_embed.moduleView source
<?php
/**
* @file
* Framework for allowing entities to be embedded in CKEditor.
*/
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Entity\ContentEntityInterface;
/**
* Implements hook_help().
*/
function entity_embed_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.entity_embed':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Entity Embed module allows entities to be embedded in formatted text.') . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Embedding media') . '</dt>';
$output .= '<dd>' . t('This module, and the text filter that it provides along with the CKEditor integration, is especially suited to allow content authors to embed media in their textual content: images, video, and so on.') . '</dd>';
$output .= '<dt>' . t('Embedding arbitrary content') . '</dt>';
$output .= '<dd>' . t('As mentioned above, this module is especially helpful for embedding media in textual content, but it is not necessarily restricted to that; it allows <em>any</em> entity to be embedded. On an e-commerce site, you may want to embed products, on a company blog you may want to embed past projects, and so on.') . '</dd>';
$output .= '</dl>';
return $output;
}
}
/**
* Implements hook_theme().
*/
function entity_embed_theme() {
return [
'entity_embed_container' => [
'render element' => 'element',
],
];
}
/**
* Prepares variables for entity embed container templates.
*
* Default template: entity-embed-container.html.twig.
*
* @param array $variables
* An associative array containing:
* - element: An associative array containing the properties of the element.
* Properties used: #attributes, #children.
*/
function template_preprocess_entity_embed_container(array &$variables) {
$variables['element'] += [
'#attributes' => [],
];
$variables['attributes'] = $variables['element']['#attributes'];
$variables['children'] = $variables['element']['#children'];
}
/**
* Implements hook_entity_embed_display_plugins_alter().
*
* Implementation on behalf of the file module.
*/
function file_entity_embed_display_plugins_alter(array &$plugins) {
// The RSS enclosure field formatter is not usable for Entity Embed.
unset($plugins['file:file_rss_enclosure']);
}
/**
* Implements hook_entity_embed_display_plugins_alter().
*
* Implementation on behalf of the taxonomy module.
*/
function taxonomy_entity_embed_display_plugins_alter(array &$plugins) {
// The RSS category field formatter is not usable for Entity Embed.
unset($plugins['entity_reference:entity_reference_rss_category']);
}
/**
* Implements hook_entity_embed_display_plugins_for_context_alter().
*
* The 'Rendered entity' formatter can not be used for files unless the
* file_entity module is available.
*
* @see https://www.drupal.org/node/2468387
*
* @todo Remove when https://www.drupal.org/node/2567919 is fixed in core.
*/
function entity_embed_entity_embed_display_plugins_for_context_alter(array &$definitions, array $context) {
if ($context['entity_type'] === 'file' && !\Drupal::moduleHandler()
->moduleExists('file_entity')) {
unset($definitions['entity_reference:entity_reference_entity_view']);
}
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function entity_embed_form_filter_format_edit_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
// Add an additional validate callback so we can ensure the order of filters
// is correct.
$form['#validate'][] = 'entity_embed_filter_format_edit_form_validate';
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function entity_embed_form_filter_format_add_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
// Add an additional validate callback so we can ensure the order of filters
// is correct.
$form['#validate'][] = 'entity_embed_filter_format_edit_form_validate';
}
/**
* Validate callback to ensure filter order and allowed_html are compatible.
*/
function entity_embed_filter_format_edit_form_validate($form, FormStateInterface $form_state) {
// This validate handler is not applicable when using the 'Configure' button.
if ($form_state
->getTriggeringElement()['#name'] === 'editor_configure') {
return;
}
$allowed_html_path = [
'filters',
'filter_html',
'settings',
'allowed_html',
];
$button_group_path = [
'editor',
'settings',
'toolbar',
'button_groups',
];
$filter_html_settings_path = [
'filters',
'filter_html',
'settings',
];
$filter_html_enabled = $form_state
->getValue([
'filters',
'filter_html',
'status',
]);
$entity_embed_enabled = $form_state
->getValue([
'filters',
'entity_embed',
'status',
]);
if ($entity_embed_enabled && $filter_html_enabled && ($allowed_html = $form_state
->getValue($allowed_html_path))) {
if ($button_groups = $form_state
->getValue($button_group_path)) {
$buttons = [];
$button_groups = json_decode($button_groups, TRUE);
if (!empty($button_groups[0])) {
foreach ($button_groups[0] as $button_group) {
foreach ($button_group['items'] as $item) {
$buttons[] = $item;
}
}
}
/** @var \Drupal\filter\Entity\FilterFormat $filter_format */
$filter_format = $form_state
->getFormObject()
->getEntity();
$filter_html = $filter_format
->filters()
->get('filter_html');
$filter_html
->setConfiguration([
'settings' => $form_state
->getValue($filter_html_settings_path),
]);
$restrictions = $filter_html
->getHTMLRestrictions();
$allowed = $restrictions['allowed'];
$embeds = \Drupal::entityTypeManager()
->getStorage('embed_button')
->loadMultiple($buttons);
/** @var \Drupal\embed\Entity\EmbedButton $embed */
foreach ($embeds as $embed) {
if ($embed
->getTypeId() !== 'entity') {
continue;
}
// Require `<drupal-entity>` HTML tag if filter_html is enabled.
if (!isset($allowed['drupal-entity'])) {
$form_state
->setError($form['filters']['settings']['filter_html']['allowed_html'], t('The %embed button requires <code><drupal-entity></code> among the allowed HTML tags.', [
'%embed' => $embed
->label(),
]));
break;
}
else {
$required_attributes = [
'data-entity-type',
'data-entity-uuid',
'data-entity-embed-display',
'data-entity-embed-display-settings',
'data-align',
'data-caption',
'data-embed-button',
'alt',
'title',
];
// If there are no attributes, the allowed item is set to FALSE,
// otherwise, it is set to an array.
if ($allowed['drupal-entity'] === FALSE) {
$missing_attributes = $required_attributes;
}
else {
// If any of the attributes on the drupal-entity tag use wildcards,
// iterate through and replace them with matching required
// attributes.
$wildcards = preg_grep('/\\*/', array_keys($allowed['drupal-entity']));
if (!empty($wildcards)) {
foreach ($wildcards as $wildcard) {
$pattern = str_replace('*', '(.*)', $wildcard);
$matches = preg_grep('/' . $pattern . '/', $required_attributes);
foreach ($matches as $match) {
$allowed['drupal-entity'][$match] = 1;
}
unset($allowed['drupal-entity'][$wildcard]);
}
}
$missing_attributes = array_diff($required_attributes, array_keys($allowed['drupal-entity']));
}
if ($missing_attributes) {
$form_state
->setError($form['filters']['settings']['filter_html']['allowed_html'], t('The <code><drupal-entity></code> tag in the allowed HTML tags is missing the following attributes: <code>%list</code>.', [
'%list' => implode(', ', $missing_attributes),
]));
break;
}
}
}
}
}
$filters = $form_state
->getValue('filters');
$get_filter_label = function ($filter_plugin_id) use ($form) {
return (string) $form['filters']['order'][$filter_plugin_id]['filter']['#markup'];
};
// The "entity_embed" filter must run after "filter_align", "filter_caption",
// and "filter_html_image_secure".
if ($entity_embed_enabled) {
$precedents = [
'filter_align',
'filter_caption',
'filter_html_image_secure',
];
$error_filters = [];
foreach ($precedents as $filter_name) {
// A filter that should run before entity embed filter.
$precedent = $filters[$filter_name];
if (empty($precedent['status']) || !isset($precedent['weight'])) {
continue;
}
if ($precedent['weight'] >= $filters['entity_embed']['weight']) {
$error_filters[$filter_name] = $get_filter_label($filter_name);
}
}
if (!empty($error_filters)) {
$singular = 'The %entity-embed-filter-label filter needs to be placed after the %filter filter.';
$plural = 'The %entity-embed-filter-label filter needs to be placed after the following filters: %filters.';
$error_message = \Drupal::translation()
->formatPlural(count($error_filters), $singular, $plural, [
'%entity-embed-filter-label' => $get_filter_label('entity_embed'),
'%filter' => reset($error_filters),
'%filters' => implode(', ', $error_filters),
]);
$form_state
->setErrorByName('filters', $error_message);
}
}
}
/**
* Implements hook_field_widget_form_alter().
*/
function entity_embed_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {
// Add a `data-entity_embed-host-entity-langcode` attribute so that
// entity_embed's JavaScript can pass the host entity's language to
// EntityEmbedDialog, allowing it to present entities in the same language.
if (!empty($element['#type']) && $element['#type'] == 'text_format') {
if (!empty($context['items']) && $context['items'] instanceof FieldItemListInterface) {
$element['#attributes']['data-entity_embed-host-entity-langcode'] = $context['items']
->getLangcode();
}
else {
$entity = $form_state
->getFormObject()
->getEntity();
if ($entity instanceof ContentEntityInterface) {
$element['#attributes']['data-entity_embed-host-entity-langcode'] = $entity
->language()
->getId();
}
}
}
}
Functions
Name | Description |
---|---|
entity_embed_entity_embed_display_plugins_for_context_alter | Implements hook_entity_embed_display_plugins_for_context_alter(). |
entity_embed_field_widget_form_alter | Implements hook_field_widget_form_alter(). |
entity_embed_filter_format_edit_form_validate | Validate callback to ensure filter order and allowed_html are compatible. |
entity_embed_form_filter_format_add_form_alter | Implements hook_form_FORM_ID_alter(). |
entity_embed_form_filter_format_edit_form_alter | Implements hook_form_FORM_ID_alter(). |
entity_embed_help | Implements hook_help(). |
entity_embed_theme | Implements hook_theme(). |
file_entity_embed_display_plugins_alter | Implements hook_entity_embed_display_plugins_alter(). |
taxonomy_entity_embed_display_plugins_alter | Implements hook_entity_embed_display_plugins_alter(). |
template_preprocess_entity_embed_container | Prepares variables for entity embed container templates. |