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..cfc308cb00aa4157635c01a165bc4927d2290598 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_by_default: + type: boolean + label: 'Provide menu link by default' diff --git a/core/modules/menu_ui/js/menu_ui.admin.js b/core/modules/menu_ui/js/menu_ui.admin.js index 9507b8d15ec8e0f638153fbcc955fb93f7f87aad..72f74f487ab2d33f238649f60ff370b2395c5bb2 100644 --- a/core/modules/menu_ui/js/menu_ui.admin.js +++ b/core/modules/menu_ui/js/menu_ui.admin.js @@ -18,7 +18,11 @@ Drupal.menuUiUpdateParentList(); // Update list of available parent menu items. - $menu.on('change', 'input', Drupal.menuUiUpdateParentList); + $menu.on( + 'change', + '.available-menus input', + Drupal.menuUiUpdateParentList, + ); } }, }; diff --git a/core/modules/menu_ui/menu_ui.post_update.php b/core/modules/menu_ui/menu_ui.post_update.php new file mode 100644 index 0000000000000000000000000000000000000000..1f1c1c6a9d4f85faf0a8423792558493f3844785 --- /dev/null +++ b/core/modules/menu_ui/menu_ui.post_update.php @@ -0,0 +1,23 @@ +update($sandbox, 'node_type', function (NodeTypeInterface $node_type): bool { + if (!$node_type->getThirdPartySettings('menu_ui')) { + return FALSE; + } + $node_type->setThirdPartySetting('menu_ui', 'link_by_default', FALSE); + return TRUE; + }); +} diff --git a/core/modules/menu_ui/src/Hook/MenuUiHooks.php b/core/modules/menu_ui/src/Hook/MenuUiHooks.php index 3ffc6748ecd1bac472df2211b42600e992ba993b..9876dafb183c71de2baa771ed60ab7f16bb24547 100644 --- a/core/modules/menu_ui/src/Hook/MenuUiHooks.php +++ b/core/modules/menu_ui/src/Hook/MenuUiHooks.php @@ -162,6 +162,12 @@ public function formNodeFormAlter(&$form, FormStateInterface $form_state) : void if (empty($parent_element)) { return; } + + $link_by_default = FALSE; + if ($form_state->getFormObject()->getOperation() == 'default') { + $link_by_default = $defaults['link_by_default']; + } + $form['menu'] = [ '#type' => 'details', '#title' => $this->t('Menu settings'), @@ -183,7 +189,7 @@ public function formNodeFormAlter(&$form, FormStateInterface $form_state) : void $form['menu']['enabled'] = [ '#type' => 'checkbox', '#title' => $this->t('Provide a menu link'), - '#default_value' => (int) (bool) $defaults['id'], + '#default_value' => (int) (bool) $defaults['id'] || $link_by_default, ]; $form['menu']['link'] = [ '#type' => 'container', @@ -326,6 +332,7 @@ public function formNodeTypeFormAlter(&$form, FormStateInterface $form_state) : 'main', ]), '#options' => $menu_options, + '#attributes' => ['class' => ['available-menus']], '#description' => $this->t('Content of this type can be placed in the selected menus.'), ]; // @todo See if we can avoid pre-loading all options by changing the form or @@ -348,6 +355,16 @@ public function formNodeTypeFormAlter(&$form, FormStateInterface $form_state) : ], ]; $options_cacheability->applyTo($form['menu']['menu_parent']); + $form['menu']['menu_link_by_default'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Provide a menu link by default when saving new content of this type.'), + '#default_value' => $type->getThirdPartySetting('menu_ui', 'link_by_default', FALSE), + '#states' => [ + 'invisible' => [ + 'input[name^="menu_options"]' => ['checked' => FALSE], + ], + ], + ]; $form['#validate'][] = static::class . ':formNodeTypeFormValidate'; $form['#entity_builders'][] = static::class . ':formNodeTypeFormBuilder'; } @@ -360,6 +377,7 @@ public function formNodeTypeFormAlter(&$form, FormStateInterface $form_state) : public function formNodeTypeFormBuilder(string $entity_type, NodeTypeInterface $type, array &$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_by_default', $form_state->getValue('menu_link_by_default')); } /** diff --git a/core/modules/menu_ui/src/MenuUiUtility.php b/core/modules/menu_ui/src/MenuUiUtility.php index 1761983b7120aaef6c3e43a244f7b91ff0c27da0..9ae629f0ba71059b133ed01aa13239d4e6ca9956 100644 --- a/core/modules/menu_ui/src/MenuUiUtility.php +++ b/core/modules/menu_ui/src/MenuUiUtility.php @@ -147,6 +147,7 @@ public function getMenuLinkDefaults(NodeInterface $node): false|array { 'menu_name' => $menu_link->getMenuName(), 'parent' => $menu_link->getParentId(), 'weight' => $menu_link->getWeight(), + 'link_by_default' => $node_type->getThirdPartySetting('menu_ui', 'link_by_default', FALSE), ]; } } @@ -167,6 +168,7 @@ public function getMenuLinkDefaults(NodeInterface $node): false|array { 'menu_name' => $menu_name, 'parent' => '', 'weight' => 0, + 'link_by_default' => $node_type->getThirdPartySetting('menu_ui', 'link_by_default', FALSE), ]; } return $defaults; diff --git a/core/modules/menu_ui/tests/fixtures/update/page_third_party_menu_ui.php b/core/modules/menu_ui/tests/fixtures/update/page_third_party_menu_ui.php new file mode 100644 index 0000000000000000000000000000000000000000..f2e3b3c9a001d73e7ccbc537b6546b5928caac78 --- /dev/null +++ b/core/modules/menu_ui/tests/fixtures/update/page_third_party_menu_ui.php @@ -0,0 +1,24 @@ +select('config') + ->fields('config', ['data']) + ->condition('collection', '') + ->condition('name', 'node.type.page') + ->execute() + ->fetchField(); +$node_type_page_config = unserialize($node_type_page_config); +$node_type_page_config['third_party_settings']['menu_ui'] = [ + 'available_menus' => ['main'], + 'parent' => 'main:', +]; +$connection->update('config') + ->fields(['data' => serialize($node_type_page_config)]) + ->condition('collection', '') + ->condition('name', 'node.type.page') + ->execute(); \ No newline at end of file diff --git a/core/modules/menu_ui/tests/src/Functional/MenuUiNodeTest.php b/core/modules/menu_ui/tests/src/Functional/MenuUiNodeTest.php index 94cd83d8b3bfa1fb08f516a6afa2940383009f8b..5a82f9fbc1671499cf50388a3813912a76deaa4b 100644 --- a/core/modules/menu_ui/tests/src/Functional/MenuUiNodeTest.php +++ b/core/modules/menu_ui/tests/src/Functional/MenuUiNodeTest.php @@ -175,6 +175,46 @@ public function testMenuNodeFormWidget(): void { $this->drupalGet('test-page'); $this->assertSession()->linkExists($node_title); + // Enable the settings "Provide menu link by default" to content type + // and verify that the "Menu Settings" enables automatically while creating + // a new node. Also verify that menu link is created when node is created. + $edit = [ + 'menu_link_by_default' => 1, + ]; + $this->drupalGet('admin/structure/types/manage/page'); + $this->submitForm($edit, 'Save'); + $this->assertSession()->pageTextContains("The content type Basic page has been updated."); + $node_title = $this->randomMachineName(); + $edit = [ + 'title[0][value]' => $node_title, + 'body[0][value]' => $this->randomString(), + ]; + $this->drupalGet('node/add/page'); + $this->assertSession()->checkboxChecked('edit-menu-enabled'); + $this->submitForm($edit, 'Save'); + $this->drupalGet('admin/structure/menu/manage/main'); + $this->assertSession()->linkExists($node_title); + + // Disable the settings "Provide menu link by default" and verify that the + // "Menu Settings" does not enable automatically while creating a new node. + // Also verify that menu link is created when node is created. + $edit = [ + 'menu_link_by_default' => 0, + ]; + $this->drupalGet('admin/structure/types/manage/page'); + $this->submitForm($edit, 'Save'); + $this->assertSession()->pageTextContains("The content type Basic page has been updated."); + $node_title = $this->randomMachineName(); + $edit = [ + 'title[0][value]' => $node_title, + 'body[0][value]' => $this->randomString(), + ]; + $this->drupalGet('node/add/page'); + $this->assertSession()->checkboxNotChecked('edit-menu-enabled'); + $this->submitForm($edit, 'Save'); + $this->drupalGet('admin/structure/menu/manage/main'); + $this->assertSession()->linkNotExists($node_title); + // Make sure the menu links only appear when the node is published. // These buttons just appear for 'administer nodes' users. $admin_user = $this->drupalCreateUser([ diff --git a/core/modules/menu_ui/tests/src/Functional/Update/MenuUiLinkByDefaultUpdateTest.php b/core/modules/menu_ui/tests/src/Functional/Update/MenuUiLinkByDefaultUpdateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..45ba207f08dfe9766adfdfe6e0a6312379eae588 --- /dev/null +++ b/core/modules/menu_ui/tests/src/Functional/Update/MenuUiLinkByDefaultUpdateTest.php @@ -0,0 +1,56 @@ +databaseDumpFiles = [ + DRUPAL_ROOT . '/core/modules/system/tests/fixtures/update/drupal-11.3.0.filled.standard.php.gz', + DRUPAL_ROOT . '/core/modules/menu_ui/tests/fixtures/update/page_third_party_menu_ui.php', + ]; + } + + /** + * Tests that link_by_default is added in node.type.page.third_party.menu_ui. + * + * @see menu_ui_post_update_add_link_by_default() + */ + public function testLinkByDefaultAddedAfterUpdate(): void { + $page_third_party_menu_ui_settings = $this->config('node.type.page')->get('third_party_settings.menu_ui'); + $this->assertArrayNotHasKey('link_by_default', $page_third_party_menu_ui_settings); + + $this->runUpdates(); + + $page_third_party_menu_ui_settings = $this->config('node.type.page')->get('third_party_settings.menu_ui'); + $this->assertNotNull($page_third_party_menu_ui_settings['link_by_default']); + $this->assertFalse($page_third_party_menu_ui_settings['link_by_default']); + } + +} diff --git a/core/modules/node/tests/src/Kernel/NodeTypeValidationTest.php b/core/modules/node/tests/src/Kernel/NodeTypeValidationTest.php index 9d8549722613bba5d48799ca461d0ff22c4771e2..e570ff66e408a288a1ae09738f0b62e7ade6d098 100644 --- a/core/modules/node/tests/src/Kernel/NodeTypeValidationTest.php +++ b/core/modules/node/tests/src/Kernel/NodeTypeValidationTest.php @@ -87,7 +87,14 @@ public function testDescriptionAndHelpCannotBeEmpty(): void { /** * Tests third party settings menu UI. */ - #[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_by_default' is a required key.", + ], + ], + ])] #[TestWith([FALSE, []])] public function testThirdPartySettingsMenuUi(bool $third_party_settings_menu_ui_fully_validatable, array $expected_validation_errors): void { $this->enableModules(['menu_ui']);