entity_reference_edit_link-1.1.2/entity_reference_edit_link.module
entity_reference_edit_link.module
<?php
/**
* @file
* This is the module to create a drop-down menu for the core toolbar.
*/
use Drupal\Core\Field\EntityReferenceFieldItemList;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Render\Element;
use Drupal\Core\Url;
use Drupal\entity_reference_edit_link\Plugin\Field\FieldWidget\EntityReferenceEditLinkAutocompleteTagsWidget;
use Drupal\entity_reference_edit_link\Plugin\Field\FieldWidget\EntityReferenceEditLinkAutocompleteWidget;
use Drupal\node\NodeForm;
use Drupal\user\Entity\User;
/**
* Implements hook_preprocess_HOOK().
*/
function entity_reference_edit_link_preprocess_field_multiple_value_form(&$variables) {
if (!isset($variables['element'][0]['_link'])) {
return;
}
// Adds link column to the table header.
$variables['table']['#header'][] = t('Edit Entity', [], ['context' => 'Link']);
$element = $variables['element'];
// Copied some part of the code from the another hook just to add the correct
// values to the render array.
/* @see \template_preprocess_field_multiple_value_form() */
foreach (Element::children($element) as $key) {
if ($key === 'add_more') {
$variables['button'] = &$element[$key];
}
else {
$items[] = &$element[$key];
}
}
foreach ($items as $item) {
$order_class = $element['#field_name'] . '-delta-order';
$item['_weight']['#attributes']['class'] = [$order_class];
// Remove weight and link form elements from item render array,
// so they can be rendered in a separate table column.
$delta_element = $item['_weight'];
$link_element = $item['_link'] ?? NULL;
unset($item['_weight']);
unset($item['_link']);
// Render actions in a separate column.
$actions = [];
if (isset($item['_actions'])) {
$actions = $item['_actions'];
unset($item['_actions']);
}
$cells = [
['data' => '', 'class' => ['field-multiple-drag']],
['data' => $item],
['data' => $actions],
['data' => $delta_element, 'class' => ['delta-order']],
// Adds link element to the render array.
['data' => $link_element, 'class' => ['reference-link']],
];
$rows[] = [
'data' => $cells,
'class' => ['draggable'],
];
}
$variables['table']['#rows'] = $rows;
}
/**
* Implements hook_field_widget_info_alter().
*/
function entity_reference_edit_link_field_widget_info_alter(array &$info) {
$info['entity_reference_autocomplete']['class'] = EntityReferenceEditLinkAutocompleteWidget::class;
$info['entity_reference_autocomplete_tags']['class'] = EntityReferenceEditLinkAutocompleteTagsWidget::class;
}
/**
* Implements hook_field_widget_complete_form_alter().
*
* @throws \Drupal\Core\Entity\EntityMalformedException
*/
function entity_reference_edit_link_field_widget_complete_form_alter(&$field_widget_complete_form, FormStateInterface $form_state, $context) {
$widget = $context['widget'] ?? NULL;
// Adds support of the select2 field widget.
if (!$widget || $widget->getPluginId() != 'select2_entity_reference') {
return;
}
$entity = !empty($context['items']) ? $context['items']->entity : NULL;
$user = User::load(\Drupal::currentUser()->id());
if (empty($entity) || !$entity->access('update', $user)) {
return;
}
$field_widget_complete_form += [
'#attached' => [
'library' => ['entity_reference_edit_link/reference.field'],
],
];
$field_widget_complete_form['widget'] = [
'target_id' => $field_widget_complete_form['widget'],
'_link' => _entity_reference_edit_link_prepare_link($widget, $context['items'], $entity),
];
}
/**
* Prepares a render array for the field edit link.
*
* @param \Drupal\Core\Field\WidgetBase $widget
* Field widget object.
* @param \Drupal\Core\Field\EntityReferenceFieldItemList $items
* Field items.
* @param \Drupal\Core\Entity\EntityInterface $entity
* Entity for the single value field case.
*
* @return array
* Returns render array with the link.
*
* @throws \Drupal\Core\Entity\EntityMalformedException
*/
function _entity_reference_edit_link_prepare_link(WidgetBase $widget, EntityReferenceFieldItemList $items, mixed $entity) {
// Check if the widget allow multiple values.
$multiple = $widget->getPluginDefinition()['multiple_values'] ?? FALSE;
// Prepares container for the link.
$link = [
'#type' => 'container',
'#attributes' => [
'class' => ['reference-edit-link-wrapper form-item'],
],
];
// Build multiple links if field widget allows multiple values.
if ($multiple) {
// Create default link value.
$links['default'] = [
'title' => t('Edit'),
'url' => Url::fromRoute('<none>'),
];
// Prepares link for the field values.
/** @var \Drupal\Core\Entity\EntityInterface $referencedEntity */
foreach ($items->referencedEntities() as $referencedEntity) {
if (!$referencedEntity->hasLinkTemplate('edit-form')) {
continue;
}
$links[$referencedEntity->id()] = [
'title' => $referencedEntity->label(),
'url' => $referencedEntity->toUrl('edit-form'),
'attributes' => [
'target' => '_blank',
],
];
}
// Render multiple links as a dropbutton.
$link['link'] = [
'#type' => 'dropbutton',
'#dropbutton_type' => 'small',
'#links' => $links,
'#attributes' => [
'class' => ['reference-edit-link'],
'target' => '_blank',
],
];
}
// Handle single value field.
elseif ($entity->hasLinkTemplate('edit-form')) {
$link['link'] = [
'#type' => 'link',
'#title' => t('Edit'),
'#url' => $entity->toUrl('edit-form'),
'#attributes' => [
'class' => ['button reference-edit-link'],
'target' => '_blank',
],
];
}
return $link;
}
/**
* Implements hook_form_alter().
*/
function entity_reference_edit_link_form_alter(&$form, FormStateInterface $form_state, $form_id) {
$formObject = $form_state->getFormObject();
// Currently worked only for the nodes.
if (!$formObject instanceof NodeForm || $formObject->getOperation() != 'edit') {
return;
}
$node = $formObject->getEntity();
if (!$node) {
return;
}
if (_entity_reference_edit_link_allowed_content_type($node) && _entity_reference_edit_link_check_permissions()) {
$form['#title'] = _entity_reference_edit_link_build_entity_type_link($node);
}
}
/**
* Implements hook_preprocess_HOOK().
*/
function entity_reference_edit_link_preprocess_page_title(&$variables) {
// To handle Gin theme node edit page structure.
$node = \Drupal::routeMatch()->getParameter('node');
// Only for the node edit pages.
if (!$node || \Drupal::routeMatch()->getRouteName() != 'entity.node.edit_form') {
return;
}
if (_entity_reference_edit_link_allowed_content_type($node) && _entity_reference_edit_link_check_permissions()) {
$variables['#title'] = _entity_reference_edit_link_build_entity_type_link($node);
}
}
/**
* Implements hook_theme_registry_alter().
*/
function entity_reference_edit_link_theme_registry_alter(&$theme_registry) {
// To run module hook function before Gin theme functions.
foreach ($theme_registry['page_title']['preprocess functions'] as $key => $value) {
if ($value == 'entity_reference_edit_link_preprocess_page_title') {
unset($theme_registry['page_title']['preprocess functions'][$key]);
$theme_registry['page_title']['preprocess functions'][] = $value;
}
}
}
/**
* Implements hook_entity().
*/
function _entity_reference_edit_link_build_entity_type_link($node) {
$url = Url::fromRoute("entity.{$node->getEntityTypeId()}.field_ui_fields", [
'node_type' => $node->bundle(),
],
[
'attributes' => ['target' => '_blank'],
]);
return t('<em>Edit @type</em> @title', [
'@type' => Link::fromTextAndUrl(node_get_type_label($node), $url)->toString(),
'@title' => $node->label(),
]);
}
/**
* Implements custom function to check allowed content types.
*/
function _entity_reference_edit_link_allowed_content_type($node) {
return !empty($allowedContentTypes = \Drupal::config('entity_reference_edit_link.config')->get('content_types'))
&& in_array($node->bundle(), $allowedContentTypes);
}
/**
* Checks user permissions.
*
* @return bool
* Returns TRUE if current user has specific permission.
*/
function _entity_reference_edit_link_check_permissions() {
return \Drupal::currentUser()->hasPermission('administer node fields');
}
