diff --git a/core/modules/content_moderation/tests/src/Functional/LayoutBuilderContentModerationIntegrationTest.php b/core/modules/content_moderation/tests/src/Functional/LayoutBuilderContentModerationIntegrationTest.php index 8d523fa406366b75492666958d3edb55026e1237..2f2ac1ed5e76f1a542fa83b908435ff7bedbf7a6 100644 --- a/core/modules/content_moderation/tests/src/Functional/LayoutBuilderContentModerationIntegrationTest.php +++ b/core/modules/content_moderation/tests/src/Functional/LayoutBuilderContentModerationIntegrationTest.php @@ -114,6 +114,7 @@ public function testLayoutModeration(): void { 'title' => 'bar', 'menu_name' => 'main', 'description' => 'view bar', + 'link_enabled' => TRUE, 'parent' => '', ]); diff --git a/core/modules/menu_ui/config/schema/menu_ui.schema.yml b/core/modules/menu_ui/config/schema/menu_ui.schema.yml index 0ec16221aad46a608d1d1f8822673322e317b94a..8a332bb7def0c5646492d280404264349b0369b0 100644 --- a/core/modules/menu_ui/config/schema/menu_ui.schema.yml +++ b/core/modules/menu_ui/config/schema/menu_ui.schema.yml @@ -23,3 +23,6 @@ node.type.*.third_party.menu_ui: parent: type: string label: 'Parent' + link_enabled: + type: boolean + label: 'Enable menu link' diff --git a/core/modules/menu_ui/menu_ui.module b/core/modules/menu_ui/menu_ui.module index cf543258433ebaece207944206611b6a6ee46def..5b09703f081d15d84e6b505a7c8907dfc8db424c 100644 --- a/core/modules/menu_ui/menu_ui.module +++ b/core/modules/menu_ui/menu_ui.module @@ -41,8 +41,8 @@ function _menu_ui_node_save(NodeInterface $node, array $values): void { 'link' => ['uri' => 'entity:node/' . $node->id()], 'langcode' => $node->language()->getId(), ]); - $entity->enabled->value = 1; } + $entity->enabled->value = $values['link_enabled'] ?? TRUE; $entity->title->value = trim($values['title']); $entity->description->value = trim($values['description']); $entity->menu_name->value = $values['menu_name']; @@ -130,6 +130,7 @@ function menu_ui_get_menu_link_defaults(NodeInterface $node) { 'menu_name' => $menu_link->getMenuName(), 'parent' => $menu_link->getParentId(), 'weight' => $menu_link->getWeight(), + 'enabled' => $menu_link->isEnabled(), ]; } } @@ -150,6 +151,7 @@ function menu_ui_get_menu_link_defaults(NodeInterface $node) { 'menu_name' => $menu_name, 'parent' => '', 'weight' => 0, + 'enabled' => $node_type->getThirdPartySetting('menu_ui', 'link_enabled', !empty($menu_name)), ]; } return $defaults; @@ -165,7 +167,7 @@ function menu_ui_node_builder($entity_type, NodeInterface $entity, &$form, FormS /** * Form submission handler for menu item field on the node form. * - * @see menu_ui_form_node_form_alter() + * @see \Drupal\menu_ui\Hook\MenuUiHooks::formNodeFormAlter() */ function menu_ui_form_node_form_submit($form, FormStateInterface $form_state): void { $node = $form_state->getFormObject()->getEntity(); @@ -197,7 +199,7 @@ function menu_ui_form_node_form_submit($form, FormStateInterface $form_state): v /** * Validate handler for forms with menu options. * - * @see menu_ui_form_node_type_form_alter() + * @see \Drupal\menu_ui\Hook\MenuUiHooks::formNodeTypeFormAlter() */ function menu_ui_form_node_type_form_validate(&$form, FormStateInterface $form_state): void { $available_menus = array_filter($form_state->getValue('menu_options')); @@ -217,11 +219,12 @@ function menu_ui_form_node_type_form_validate(&$form, FormStateInterface $form_s /** * Entity builder for the node type form with menu options. * - * @see menu_ui_form_node_type_form_alter() + * @see \Drupal\menu_ui\Hook\MenuUiHooks::formNodeTypeFormAlter() */ function menu_ui_form_node_type_form_builder($entity_type, NodeTypeInterface $type, &$form, FormStateInterface $form_state): void { $type->setThirdPartySetting('menu_ui', 'available_menus', array_values(array_filter($form_state->getValue('menu_options')))); $type->setThirdPartySetting('menu_ui', 'parent', $form_state->getValue('menu_parent')); + $type->setThirdPartySetting('menu_ui', 'link_enabled', $form_state->getValue('link_enabled')); } /** diff --git a/core/modules/menu_ui/src/Hook/MenuUiHooks.php b/core/modules/menu_ui/src/Hook/MenuUiHooks.php index 9b32ffa182476332a0516980346f9d09bad7f223..810f8637c92b2a38b8434e8727d2f00ff4a78d94 100644 --- a/core/modules/menu_ui/src/Hook/MenuUiHooks.php +++ b/core/modules/menu_ui/src/Hook/MenuUiHooks.php @@ -222,6 +222,13 @@ public function formNodeFormAlter(&$form, FormStateInterface $form_state) : void '#default_value' => $defaults['weight'], '#description' => $this->t('Menu links with lower weights are displayed before links with higher weights.'), ]; + $form['menu']['link']['link_enabled'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Enabled'), + '#description' => $this->t('A flag for whether the link should be enabled in menus or hidden.'), + '#default_value' => $defaults['enabled'] ?? TRUE, + ]; + foreach (array_keys($form['actions']) as $action) { if ($action != 'preview' && isset($form['actions'][$action]['#type']) && $form['actions'][$action]['#type'] === 'submit') { $form['actions'][$action]['#submit'][] = 'menu_ui_form_node_form_submit'; @@ -287,6 +294,11 @@ public function formNodeTypeFormAlter(&$form, FormStateInterface $form_state) : ], ]; $options_cacheability->applyTo($form['menu']['menu_parent']); + $form['menu']['link_enabled'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Enable menu link (default)'), + '#default_value' => $type->getThirdPartySetting('menu_ui', 'link_enabled', TRUE), + ]; $form['#validate'][] = 'menu_ui_form_node_type_form_validate'; $form['#entity_builders'][] = 'menu_ui_form_node_type_form_builder'; } diff --git a/core/modules/menu_ui/tests/src/Functional/MenuUiContentModerationTest.php b/core/modules/menu_ui/tests/src/Functional/MenuUiContentModerationTest.php index 95dc030ba80462f5100df749086bba4a81b1e318..96bdff67b7d01e1cb782b16c454487987231c20c 100644 --- a/core/modules/menu_ui/tests/src/Functional/MenuUiContentModerationTest.php +++ b/core/modules/menu_ui/tests/src/Functional/MenuUiContentModerationTest.php @@ -86,6 +86,7 @@ public function testMenuUiWithPendingRevisions(): void { // Add a menu link and save a new default (published) revision. $edit = [ 'menu[enabled]' => 1, + 'menu[link_enabled]' => TRUE, 'menu[title]' => 'Test menu link', 'moderation_state[0][state]' => 'published', ]; @@ -121,6 +122,7 @@ public function testMenuUiWithPendingRevisions(): void { // Try to delete the menu link and save a new non-default (draft) revision. $edit = [ 'menu[enabled]' => 0, + 'menu[link_enabled]' => FALSE, 'moderation_state[0][state]' => 'draft', ]; $this->drupalGet('node/' . $node->id() . '/edit'); @@ -171,6 +173,7 @@ public function testMenuUiWithPendingRevisions(): void { // and ensure it's not immediately published. $edit = [ 'menu[enabled]' => 1, + 'menu[link_enabled]' => TRUE, 'menu[title]' => 'Second test menu link', 'moderation_state[0][state]' => 'draft', ]; diff --git a/core/modules/menu_ui/tests/src/Functional/MenuUiNodeTest.php b/core/modules/menu_ui/tests/src/Functional/MenuUiNodeTest.php index 0025ae08718c9e0673ba495b99551b5151db0794..a160181480cdec8e99505923ba5c6cf5739b086b 100644 --- a/core/modules/menu_ui/tests/src/Functional/MenuUiNodeTest.php +++ b/core/modules/menu_ui/tests/src/Functional/MenuUiNodeTest.php @@ -72,6 +72,35 @@ protected function setUp(): void { $this->drupalLogin($this->editor); } + /** + * Test correct configuring of default enabling link setting by content type. + */ + public function testContentTypeLinkEnableConfiguration(): void { + // Check that the non-configured content type defaults to enabled links. + $this->drupalGet('node/add/page'); + $this->assertSession()->checkboxChecked('menu[link_enabled]'); + + // Configure menu links to be disabled. + $edit = [ + 'menu_options[main]' => 1, + 'menu_parent' => 'main:', + 'link_enabled' => FALSE, + ]; + $this->drupalGet('admin/structure/types/manage/page'); + $this->submitForm($edit, 'Save'); + $this->assertSession()->pageTextContains('The content type Basic page has been updated.'); + $this->drupalGet('node/add/page'); + $this->assertSession()->checkboxNotChecked('menu[link_enabled]'); + + // Configure menu links to be enabled. + $edit['link_enabled'] = TRUE; + $this->drupalGet('admin/structure/types/manage/page'); + $this->submitForm($edit, 'Save'); + $this->assertSession()->pageTextContains('The content type Basic page has been updated.'); + $this->drupalGet('node/add/page'); + $this->assertSession()->checkboxChecked('menu[link_enabled]'); + } + /** * Tests creating, editing, deleting menu links via node form widget. */ @@ -132,6 +161,7 @@ public function testMenuNodeFormWidget(): void { 'menu_options[main]' => 1, 'menu_options[tools]' => 1, 'menu_parent' => 'main:', + 'link_enabled' => TRUE, ]; $this->drupalGet('admin/structure/types/manage/page'); $this->submitForm($edit, 'Save'); @@ -142,6 +172,7 @@ public function testMenuNodeFormWidget(): void { 'title[0][value]' => $node_title, 'menu[enabled]' => 1, 'menu[title]' => 'Test preview', + 'menu[link_enabled]' => TRUE, ]; $this->drupalGet('node/add/page'); $this->submitForm($edit, 'Preview'); @@ -185,6 +216,7 @@ public function testMenuNodeFormWidget(): void { 'menu[enabled]' => 1, 'menu[title]' => $node_title, 'status[value]' => FALSE, + 'menu[link_enabled]' => TRUE, ]; $this->drupalGet('node/' . $node->id() . '/edit'); $this->submitForm($edit, 'Save'); @@ -199,13 +231,34 @@ public function testMenuNodeFormWidget(): void { $this->drupalGet('test-page'); $this->assertSession()->linkExists($node_title, 0, 'Found a menu link with the node published'); + // Assert that link is not enabled / does not exist in the rendered menu + // if link_enabled option is disabled. + $edit['menu[link_enabled]'] = FALSE; + $this->drupalGet('node/' . $node->id() . '/edit'); + $this->submitForm($edit, 'Save'); + $this->drupalGet('test-page'); + $this->assertSession()->linkNotExists($node_title, 'Found no menu link with the node menu link disabled'); + // If we go to main menu we shall see the disabled menu link. + $this->drupalGet('admin/structure/menu/manage/main'); + $this->assertSession()->checkboxNotChecked("Enable $node_title menu link"); + // Re-enable link via node form and check menu. + $edit['menu[link_enabled]'] = TRUE; + $this->drupalGet('node/' . $node->id() . '/edit'); + $this->submitForm($edit, 'Save'); + $this->drupalGet('test-page'); + // If we go to main menu we shall see the enabled menu link. + $this->drupalGet('admin/structure/menu/manage/main'); + $this->assertSession()->checkboxChecked("Enable $node_title menu link"); + // Log back in as normal user. $this->drupalLogin($this->editor); + // Edit the node and create a menu link. $edit = [ 'menu[enabled]' => 1, 'menu[title]' => $node_title, 'menu[weight]' => 17, + 'menu[link_enabled]' => TRUE, ]; $this->drupalGet('node/' . $node->id() . '/edit'); $this->submitForm($edit, 'Save'); @@ -229,6 +282,8 @@ public function testMenuNodeFormWidget(): void { $link->set('enabled', FALSE); $link->save(); $this->drupalGet($node->toUrl('edit-form')); + // Remove this submission value as it will re-enable menu link on save. + unset($edit['menu[link_enabled]']); $this->submitForm($edit, 'Save'); $link = MenuLinkContent::load($link_id); $this->assertFalse($link->isEnabled(), 'Saving a node with a disabled menu link keeps the menu link disabled.'); @@ -335,6 +390,7 @@ public function testMultilingualMenuNodeFormWidget(): void { 'menu[enabled]' => 1, 'menu[title]' => $node_title, 'menu[weight]' => 17, + 'menu[link_enabled]' => TRUE, ]; $options = ['language' => $languages[$langcodes[0]]]; $url = $node->toUrl('edit-form', $options); @@ -346,6 +402,7 @@ public function testMultilingualMenuNodeFormWidget(): void { 'menu[enabled]' => 1, 'menu[title]' => $translated_node_title, 'menu[weight]' => 17, + 'menu[link_enabled]' => TRUE, ]; $options = ['language' => $languages[$langcodes[1]]]; $url = $node->toUrl('edit-form', $options); diff --git a/core/modules/node/tests/src/Kernel/NodeTypeValidationTest.php b/core/modules/node/tests/src/Kernel/NodeTypeValidationTest.php index 0761342277a2ab84eb0679783aa874ff5073ecfb..1f4ce4f1d3333b0336c7995638565669f0167ac4 100644 --- a/core/modules/node/tests/src/Kernel/NodeTypeValidationTest.php +++ b/core/modules/node/tests/src/Kernel/NodeTypeValidationTest.php @@ -81,7 +81,7 @@ public function testDescriptionAndHelpCannotBeEmpty(): void { } /** - * @testWith [true, {"third_party_settings.menu_ui": "'parent' is a required key."}] + * @testWith [true, {"third_party_settings.menu_ui": ["'parent' is a required key.", "'link_enabled' is a required key."]}] * [false, {}] */ public function testThirdPartySettingsMenuUi(bool $third_party_settings_menu_ui_fully_validatable, array $expected_validation_errors): void {