diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module index cffccde..ed33b14 100644 --- a/core/modules/menu_ui/menu_ui.module +++ b/core/modules/menu_ui/menu_ui.module @@ -71,6 +71,10 @@ function menu_ui_entity_type_build(array &$entity_types) { ->setLinkTemplate('edit-form', '/admin/structure/menu/manage/{menu}') ->setLinkTemplate('add-link-form', '/admin/structure/menu/manage/{menu}/add') ->setLinkTemplate('collection', '/admin/structure/menu'); + + if (isset($entity_types['node'])) { + $entity_types['node']->addConstraint('MenuSettings', []); + } } /** @@ -357,6 +361,15 @@ function menu_ui_form_node_form_alter(&$form, FormStateInterface $form_state) { $form['actions'][$action]['#submit'][] = 'menu_ui_form_node_form_submit'; } } + + $form['#entity_builders'][] = 'menu_ui_node_builder'; +} + +/** + * Entity form builder to add the menu information to the node. + */ +function menu_ui_node_builder($entity_type, NodeInterface $entity, &$form, FormStateInterface $form_state) { + $entity->menu = $form_state->getValue('menu'); } /** diff --git a/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraint.php b/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraint.php new file mode 100644 index 0000000..2081ea3 --- /dev/null +++ b/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraint.php @@ -0,0 +1,19 @@ +published version of this content.'; + +} diff --git a/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraintValidator.php b/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraintValidator.php new file mode 100644 index 0000000..a27cbe9 --- /dev/null +++ b/core/modules/menu_ui/src/Plugin/Validation/Constraint/MenuSettingsConstraintValidator.php @@ -0,0 +1,62 @@ +isNew() && !$entity->isDefaultRevision()) { + $defaults = menu_ui_get_menu_link_defaults($entity); + $values = $entity->menu; + $violation_path = NULL; + + if (trim($values['title']) && !empty($values['menu_parent'])) { + list($menu_name, $parent) = explode(':', $values['menu_parent'], 2); + $values['menu_name'] = $menu_name; + $values['parent'] = $parent; + } + + // Handle the case when a menu link is added to a forward revision. + if ($defaults['entity_id'] != $values['entity_id']) { + $violation_path = 'menu'; + } + // Handle the case when the menu link is deleted in a forward revision. + elseif (empty($values['enabled'] && $values['entity_id'])) { + $violation_path = 'menu'; + } + // Handle all the other menu link changes in a forward revision. + elseif (($values['title'] != $defaults['title'])) { + $violation_path = 'menu.title'; + } + elseif (($values['description'] != $defaults['description'])) { + $violation_path = 'menu.description'; + } + elseif (($values['menu_name'] != $defaults['menu_name'])) { + $violation_path = 'menu.menu_parent'; + } + elseif (($values['parent'] != $defaults['parent'])) { + $violation_path = 'menu.menu_parent'; + } + elseif (($values['weight'] != $defaults['weight'])) { + $violation_path = 'menu.weight'; + } + + if ($violation_path) { + $this->context->buildViolation($constraint->message) + ->atPath($violation_path) + ->setInvalidValue($entity) + ->addViolation(); + } + } + } + +} diff --git a/core/modules/menu_ui/tests/src/Functional/MenuUiContentModerationTest.php b/core/modules/menu_ui/tests/src/Functional/MenuUiContentModerationTest.php new file mode 100644 index 0000000..85eb6ad --- /dev/null +++ b/core/modules/menu_ui/tests/src/Functional/MenuUiContentModerationTest.php @@ -0,0 +1,131 @@ +drupalPlaceBlock('system_menu_block:main'); + + // Create a 'page' content type. + $this->drupalCreateContentType([ + 'type' => 'page', + 'name' => 'Basic page', + 'display_submitted' => FALSE, + ]); + + $workflow = Workflow::load('editorial'); + $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'page'); + $workflow->save(); + } + + /** + * Tests that node drafts can not modify the menu settings. + */ + public function testMenuUiWithForwardRevisions() { + $editor = $this->drupalCreateUser([ + 'administer nodes', + 'administer menu', + 'create page content', + 'edit any page content', + 'use editorial transition create_new_draft', + 'use editorial transition publish', + 'view latest version', + 'view any unpublished content', + ]); + $this->drupalLogin($editor); + + // Create a node. + $node = $this->drupalCreateNode(); + + // Add a menu link and save a new default (published) revision. + $edit = [ + 'menu[enabled]' => 1, + 'menu[title]' => 'Test menu link', + ]; + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and Publish')); + + $this->assertSession()->linkExists('Test menu link'); + + // Try to change the menu link title and save a new non-default (draft) + // revision. + $edit = [ + 'menu[title]' => 'Test menu link draft', + ]; + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and Create New Draft')); + + // Check that the menu settings were not applied. + $this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.'); + $this->assertSession()->linkExists('Test menu link'); + $this->assertSession()->linkNotExists('Test menu link draft'); + + // Try to change the menu link description and save a new non-default + // (draft) revision. + $edit = [ + 'menu[description]' => 'Test menu link description', + ]; + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and Create New Draft')); + + // Check that the menu settings were not applied. + $this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.'); + + // Try to change the menu link weight and save a new non-default (draft) + // revision. + $edit = [ + 'menu[weight]' => 1, + ]; + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and Create New Draft')); + + // Check that the menu settings were not applied. + $this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.'); + + // Try to change the menu link parent and save a new non-default (draft) + // revision. + $edit = [ + 'menu[menu_parent]' => 'main:test_page_test.front_page', + ]; + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and Create New Draft')); + + // Check that the menu settings were not applied. + $this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.'); + + // Try to delete the menu link and save a new non-default (draft) revision. + $edit = [ + 'menu[enabled]' => 0, + ]; + $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and Create New Draft')); + + // Check that the menu settings were not applied. + $this->assertSession()->pageTextContains('You can only change the menu settings for the published version of this content.'); + $this->assertSession()->linkExists('Test menu link'); + + // Try to save a new non-default (draft) revision without any changes and + // check that the error message is not shown. + $this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save and Create New Draft')); + + // Check that the menu settings were not applied. + $this->assertSession()->pageTextNotContains('You can only change the menu settings for the published version of this content.'); + $this->assertSession()->linkExists('Test menu link'); + } + +}