menu_link_content_revisions_ui-1.0.0/menu_link_content_revisions_ui.module
menu_link_content_revisions_ui.module
<?php
/**
* @file
* Module file for the menu_link_content_revisions_ui module.
*/
use Drupal\Component\Utility\DeprecationHelper;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Form\RevisionDeleteForm;
use Drupal\Core\Entity\Form\RevisionRevertForm;
use Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\menu_link_content\MenuLinkContentInterface;
/**
* Implements hook_theme().
*
* Add a theme hook, so it is possible to customize the output.
*/
function menu_link_content_revisions_ui_theme(): array {
$theme = [];
$theme['menu_link_content'] = [
'render element' => 'elements',
'file' => 'menu_link_content_revisions_ui.theme.inc',
];
return $theme;
}
/**
* Implements hook_entity_operation_alter().
*
* Add 'Revisions' to menu link content entity operations.
*/
function menu_link_content_revisions_ui_entity_operation_alter(array &$operations, EntityInterface $entity): void {
$current_user = \Drupal::currentUser();
if ($current_user->hasPermission('view all menu link content revisions')) {
$type = $entity->getEntityTypeId();
if ($type === 'menu_link_content') {
$operations['revisions'] = [
'title' => t('Revisions'),
'url' => Url::fromRoute('entity.menu_link_content.version_history', [
'menu_link_content' => $entity->id(),
]),
'weight' => 100,
];
}
}
}
/**
* Implements hook_entity_type_alter().
*
* Add Revision UI support for the menu_link_content entity type.
*
* See https://www.drupal.org/node/3160443.
*/
function menu_link_content_revisions_ui_entity_type_alter(array &$entity_types): void {
/** @var \Drupal\Core\Entity\ContentEntityType $menuLinkDefinition */
$menuLinkDefinition = $entity_types['menu_link_content'];
// Route Providers.
$handlers = $menuLinkDefinition->getHandlerClasses();
$routeProviders = $handlers['route_provider'] ?? [];
$class = RevisionHtmlRouteProvider::class;
if (!in_array($class, $routeProviders)) {
$routeProviders[] = $class;
$menuLinkDefinition->setHandlerClass('route_provider', $routeProviders);
}
// Link templates.
if (FALSE === $menuLinkDefinition->getLinkTemplate('revision')) {
$menuLinkDefinition->setLinkTemplate('revision', '/menu_link_content/{menu_link_content}/revisions/{menu_link_content_revision}/view');
}
if (FALSE === $menuLinkDefinition->getLinkTemplate('version-history')) {
$menuLinkDefinition->setLinkTemplate('version-history', '/menu_link_content/{menu_link_content}/revisions');
}
if (FALSE === $menuLinkDefinition->getLinkTemplate('revision-delete-form')) {
$menuLinkDefinition->setLinkTemplate('revision-delete-form', '/menu_link_content/{menu_link_content}/revisions/{menu_link_content_revision}/delete');
}
if (FALSE === $menuLinkDefinition->getLinkTemplate('revision-revert-form')) {
$menuLinkDefinition->setLinkTemplate('revision-revert-form', '/menu_link_content/{menu_link_content}/revisions/{menu_link_content_revision}/revert');
}
if (NULL === $menuLinkDefinition->getFormClass('revision-revert')) {
$menuLinkDefinition->setFormClass('revision-revert', RevisionRevertForm::class);
}
if (NULL === $menuLinkDefinition->getFormClass('revision-delete')) {
$menuLinkDefinition->setFormClass('revision-delete', RevisionDeleteForm::class);
}
}
/**
* Implements hook_ENTITY_TYPE_access().
*
* Add permission for viewing menu link revisions without admin menu access.
*/
function menu_link_content_revisions_ui_menu_link_content_access(EntityInterface $entity, $operation, AccountInterface $account): AccessResult {
// Revert/delete operations will always be allowed if the user has the
// "administer menu" permission since that is the admin permission on menu
// link content entities and explicitly allows access to all operations.
return match ($operation) {
'view all revisions', 'view revision' => AccessResult::allowedIfHasPermission($account, 'view all menu link content revisions'),
default => AccessResult::neutral()
};
}
/**
* Implements hook_ENTITY_TYPE_presave().
*
* Create a new revision of menu link content when auto revisions is enabled.
*/
function menu_link_content_revisions_ui_menu_link_content_presave(MenuLinkContentInterface $menu_link_content): void {
// Get the configuration settings.
$config = \Drupal::config('menu_link_content_revisions_ui.settings');
if ($config->get('enable_auto_revisions')) {
$form_id = \Drupal::request()->get('form_id');
$message = '';
// If the form ID starts with 'node_', this is a node form.
if (str_starts_with($form_id, 'node_')) {
// Only create a new revision if the menu link changed.
$original = DeprecationHelper::backwardsCompatibleCall(
\Drupal::VERSION,
'11.2',
// @phpstan-ignore-next-line
fn () => $menu_link_content->getOriginal() ?: $menu_link_content,
fn () => $menu_link_content->original ?? $menu_link_content,
);
if ($menu_link_content->isNew()) {
// Creating a new menu link.
$message = $config->get('node_add_message');
}
// Updating an existing menu link.
elseif ($original instanceof MenuLinkContentInterface) {
// These are the only fields exposed in the node form.
// Need to update this list if more fields are added.
// Example: https://www.drupal.org/project/drupal/issues/3075230
$fields_to_check = [
'title',
'description',
'weight',
'parent',
];
$updated = FALSE;
foreach ($fields_to_check as $field) {
if ($menu_link_content->get($field)->getString() !== $original->get($field)->getString()) {
$message = $config->get('node_update_message');
$updated = TRUE;
break;
}
}
if (!$updated) {
// If nothing changed, don't create a new revision.
return;
}
}
else {
// Something else is going on; don't create a new revision.
return;
}
}
// If the form ID is 'menu_edit_form', this is the menu form.
elseif ($form_id === 'menu_edit_form') {
// Can only reorder or disable/enable in the menu form.
$message = $config->get('menu_edit_message');
}
// Otherwise this is the menu link content form.
else {
if ($menu_link_content->isNew()) {
$message = $config->get('menu_link_add_message');
}
else {
$message = $config->get('menu_link_update_message');
}
}
$menu_link_content->setNewRevision();
$menu_link_content->setRevisionTranslationAffected(TRUE);
$menu_link_content->setRevisionUserId(\Drupal::currentUser()->id());
$menu_link_content->setRevisionCreationTime(\Drupal::time()->getRequestTime());
if ($config->get('append_menu_link_status')) {
// Append the menu link status to the message.
$enabled = $menu_link_content->get('enabled')->getString();
if ($enabled === '1') {
$message .= ' (enabled)';
}
else {
$message .= ' (disabled)';
}
}
$menu_link_content->setRevisionLogMessage(t('@source', ['@source' => $message]));
}
}
