multiple_node_menu.module in Multiple Node Menu 8
Same filename and directory in other branches
Add multiple menu management capabilities to node form.
File
multiple_node_menu.moduleView source
<?php
/**
* @file
* Add multiple menu management capabilities to node form.
*/
use Drupal\Core\Form\FormStateInterface;
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\node\NodeInterface;
/**
* Returns the definition for a menu link for the given node.
*
* @param \Drupal\node\NodeInterface $node
* The node entity.
*
* @return array
* An array that contains default values for the menu link form.
*/
function multiple_node_menu_get_menu_link_defaults(NodeInterface $node) {
// Prepare the definition for the edit form.
/** @var \Drupal\node\NodeTypeInterface $node_type */
$node_type = $node->type->entity;
$menu_name = strtok($node_type
->getThirdPartySetting('menu_ui', 'parent', 'main:'), ':');
$defaults = [];
if ($node
->id()) {
$id = FALSE;
// Give priority to the default menu.
$type_menus = $node_type
->getThirdPartySetting('menu_ui', 'available_menus', [
'main',
]);
if (in_array($menu_name, $type_menus)) {
$query = \Drupal::entityQuery('menu_link_content')
->condition('link.uri', 'node/' . $node
->id())
->condition('menu_name', $menu_name)
->sort('id', 'ASC')
->range(0, 1);
$result = $query
->execute();
$id = !empty($result) ? reset($result) : FALSE;
}
$ids = [];
// Check all allowed menus if a link does not exist in the default menu.
if (!$id && !empty($type_menus)) {
$query = \Drupal::entityQuery('menu_link_content')
->condition('link.uri', 'entity:node/' . $node
->id())
->condition('menu_name', array_values($type_menus), 'IN')
->sort('id', 'ASC');
$result = $query
->execute();
$ids = $result;
}
if ($ids) {
foreach ($ids as $key => $id) {
$menu_link = MenuLinkContent::load($id);
$menu_link = \Drupal::service('entity.repository')
->getTranslationFromContext($menu_link);
// kint($menu_link);
$defaults[] = [
'entity_id' => $menu_link
->id(),
'id' => $menu_link
->getPluginId(),
'title' => $menu_link
->getTitle(),
'title_max_length' => $menu_link
->getFieldDefinitions()['title']
->getSetting('max_length'),
'description' => $menu_link
->getDescription(),
'menu_name' => $menu_link
->getMenuName(),
'parent' => $menu_link
->getParentId(),
'weight' => $menu_link
->getWeight(),
'enabled' => $menu_link->enabled->value,
];
}
}
}
if (!$defaults) {
// Get the default max_length of a menu link title from the base field
// definition.
/** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */
$entity_field_manager = \Drupal::service('entity_field.manager');
$field_definitions = $entity_field_manager
->getBaseFieldDefinitions('menu_link_content');
$max_length = $field_definitions['title']
->getSetting('max_length');
$defaults[] = [
'entity_id' => 0,
'id' => '',
'title' => '',
'title_max_length' => $max_length,
'description' => '',
'menu_name' => $menu_name,
'parent' => '',
'weight' => 0,
];
}
return $defaults;
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*
* Add multiple menu items management capability to node form.
*/
function multiple_node_menu_form_node_form_alter(&$form, FormStateInterface &$form_state, $form_id) {
$node = $form_state
->getFormObject()
->getEntity();
$node_type = $node->type->entity;
$defaults = multiple_node_menu_get_menu_link_defaults($node);
$menu_names = menu_ui_get_menus();
$type_menus = $node_type
->getThirdPartySetting('menu_ui', 'available_menus', [
'main',
]);
// If no menu is allowed in the node we don't need multiple_node_menu.
if (empty($type_menus)) {
return;
}
$available_menus = [];
foreach ($type_menus as $menu) {
$available_menus[$menu] = $menu_names[$menu];
}
$menu_parent_selector = \Drupal::service('menu.parent_form_selector');
$form['menu']['menu_form_node'] = [
'#type' => 'details',
'#title' => t('Menu Form Nodes'),
'#prefix' => '<div id="multiple-node-menu-wrapper">',
'#suffix' => '</div>',
'#open' => TRUE,
'#states' => [
'invisible' => [
'input[name="menu[enabled]"]' => [
'checked' => FALSE,
],
],
],
];
$values = \Drupal::state()
->get('menu_options_' . $node
->bundle());
$links_count = \Drupal::state()
->get('menu_options_' . $node
->bundle() . 'links_count');
for ($i = 0; $i <= $links_count; $i++) {
if ($defaults[$i]) {
$default = $defaults[$i]['menu_name'] . ':' . $defaults[$i]['parent'];
}
else {
$default = $node_type
->getThirdPartySetting('menu_ui', 'parent', 'main:');
}
$parent_element = $menu_parent_selector
->parentSelectElement($default, $defaults[$i]['id'], $available_menus);
foreach ([
'id',
'entity_id',
] as $key) {
$form['menu']['menu_form_node'][$i][$key] = [
'#type' => 'value',
'#value' => $defaults[$i][$key],
];
}
$form['menu']['menu_form_node'][$i]['title'] = [
'#type' => 'textfield',
'#title' => t('Menu link title'),
'#default_value' => $defaults[$i]['title'],
];
$form['menu']['menu_form_node'][$i]['description'] = [
'#type' => 'textarea',
'#title' => t('Description'),
'#default_value' => $defaults[$i]['description'],
'#rows' => 1,
'#description' => t('Shown when hovering over the menu link.'),
];
$form['menu']['menu_form_node'][$i]['menu_parent'] = $parent_element;
$form['menu']['menu_form_node'][$i]['enabled'] = [
'#type' => 'checkbox',
'#title' => t('Enabled'),
'#default_value' => (int) (bool) isset($defaults[$i]['enabled']) ? $defaults[$i]['enabled'] : 0,
];
$form['menu']['menu_form_node'][$i]['delete'] = [
'#type' => 'submit',
'#value' => t('Delete'),
'#submit' => [
'multiple_node_menu_remove_link_submit',
],
'#ajax' => [
'callback' => 'multiple_node_menu_ajax_callback',
'wrapper' => 'multiple-node-menu-wrapper',
],
];
}
$form['menu']['menu_form_node']['add_link_submit'] = [
'#type' => 'submit',
'#value' => t('Add new menu link'),
'#submit' => [
'multiple_node_menu_add_link_submit',
],
'#ajax' => [
'callback' => 'multiple_node_menu_ajax_callback',
'wrapper' => 'multiple-node-menu-wrapper',
],
];
foreach (array_keys($form['actions']) as $action) {
if ($action != 'preview' && isset($form['actions'][$action]['#type']) && $form['actions'][$action]['#type'] === 'submit') {
$form['actions'][$action]['#submit'][] = 'multiple_node_menu_node_form_submit';
}
}
}
/**
* Form submission handler for menu item field on the node form.
*
* @see menu_ui_form_node_form_alter()
*/
function multiple_node_menu_node_form_submit($form, FormStateInterface $form_state) {
$values = $form_state
->getValue('menu')['menu_form_node'];
$node = $form_state
->getFormObject()
->getEntity();
\Drupal::state()
->set('menu_options_' . $node
->bundle(), $values);
foreach ($values as $value) {
$value['menu_name'] = "main";
$value['parent'] = str_replace('main:', '', $value['menu_parent']);
_multiple_node_menu_node_save($node, $value);
}
}
/**
* Helper function to create or update a menu link for a node.
*
* @param \Drupal\node\NodeInterface $node
* Node entity.
* @param array $values
* Values for the menu link.
*/
function _multiple_node_menu_node_save(NodeInterface $node, array $values) {
/** @var \Drupal\menu_link_content\MenuLinkContentInterface $entity */
if (!empty($values['entity_id'])) {
$entity = MenuLinkContent::load($values['entity_id']);
if ($entity
->isTranslatable()) {
if (!$entity
->hasTranslation($node
->language()
->getId())) {
$entity = $entity
->addTranslation($node
->language()
->getId(), $entity
->toArray());
}
else {
$entity = $entity
->getTranslation($node
->language()
->getId());
}
}
// Update enabled value.
$entity->enabled->value = $values['enabled'];
}
else {
// Create a new menu_link_content entity.
$entity = MenuLinkContent::create([
'link' => [
'uri' => 'entity:node/' . $node
->id(),
],
'langcode' => $node
->language()
->getId(),
]);
$entity->enabled->value = 1;
}
$entity->title->value = trim($values['title']);
$entity->description->value = trim($values['description']);
$entity->menu_name->value = $values['menu_name'];
$entity->parent->value = $values['parent'];
$entity->weight->value = isset($values['weight']) ? $values['weight'] : 0;
$entity
->save();
}
/**
* Ajax callback for multiple menu link forms.
*/
function multiple_node_menu_ajax_callback(array $form, FormStateInterface $form_state) {
return $form['menu']['menu_form_node'];
}
/**
* Submit handler for 'Add menu link' button.
*/
function multiple_node_menu_add_link_submit(array $form, FormStateInterface $form_state) {
$node = $form_state
->getFormObject()
->getEntity();
$links_count = \Drupal::state()
->get('menu_options_' . $node
->bundle() . 'links_count');
$links_count++;
\Drupal::state()
->set('menu_options_' . $node
->bundle() . 'links_count', $links_count);
$form_state
->setRebuild();
}
/**
* Submit handler for "remove" button.
*/
function multiple_node_menu_remove_link_submit($form, &$form_state) {
$node = $form_state
->getFormObject()
->getEntity();
$links_count = \Drupal::state()
->get('menu_options_' . $node
->bundle() . 'links_count');
$links_count--;
\Drupal::state()
->set('menu_options_' . $node
->bundle() . 'links_count', $links_count);
}
Functions
Name | Description |
---|---|
multiple_node_menu_add_link_submit | Submit handler for 'Add menu link' button. |
multiple_node_menu_ajax_callback | Ajax callback for multiple menu link forms. |
multiple_node_menu_form_node_form_alter | Implements hook_form_BASE_FORM_ID_alter(). |
multiple_node_menu_get_menu_link_defaults | Returns the definition for a menu link for the given node. |
multiple_node_menu_node_form_submit | Form submission handler for menu item field on the node form. |
multiple_node_menu_remove_link_submit | Submit handler for "remove" button. |
_multiple_node_menu_node_save | Helper function to create or update a menu link for a node. |