Skip to content
Snippets Groups Projects
Commit df47a5a8 authored by Steve Wirt's avatar Steve Wirt
Browse files

Issue #3406650 by swirt, davidmpickett, jordan.wood, mkinnune, skyriter:...

Issue #3406650 by swirt, davidmpickett, jordan.wood, mkinnune, skyriter: Create method to arrange multiple menu items to match a pattern
parent 9f457181
Branches
Tags
No related merge requests found
......@@ -70,3 +70,56 @@ There is currently nothing similar.
$menuManipulator = new MenuManipulator('MENU_MACHINE_NAME');
$highest_weight_used = $menuManipulator->menuSeparate();
```
### Move existing menu items to new to different weights under the same parent.
```php
use Drupal\codit_menu_tools\MenuManipulator;
$menuManipulator = new MenuManipulator('MENU_MACHINE_NAME');
$menuManipulator->moveMenuItem(
$item_title = "the menu item title",
$parent_title = "the title of the parent to look under",
$sibling_title = "The title of the sibling to move it adjacent to",
$below = TRUE, // Place it just above or just below the sibling.
$last_run = TRUE, // If moving a bunch of items, set this to FALSE, except
// for the last thing you move, then set it to TRUE.
);
```
### Move a bunch of menu items to align with a pattern.
This moves menu items up or down under the same parent so that the order
reflects what is in the pattern.
This can NOT be used to change a menu item's parent.
```php
use Drupal\codit_menu_tools\MenuManipulator;
// A simple pattern affecting items without specifying a parent.
$pattern = [
'item 1',
'item 2',
'item 3',
'item 4',
];
// A more complex pattern involving multiple parents. This would rearrange
// the subsets AND the parents.
$pattern = [
'parent1' => [
'subset_1_a',
'subset_1_b',
'subset_1_c',
]
'parent2' => [
'subset_2_a',
'subset_2_b',
'subset_2_c',
]
];
$menuManipulator = new MenuManipulator('MENU_MACHINE_NAME');
$menuManipulator->matchPattern($pattern);
```
......@@ -42,6 +42,40 @@ class MenuManipulator extends MenuManipulatorBase implements MenuManipulatorInte
return $result;
}
/**
* {@inheritdoc}
*/
public function matchPattern(array $pattern, string $parent = ''): void {
$max_loops = count($pattern);
$keys = array_keys($pattern);
$i = 0;
foreach ($pattern as $index => $item) {
if (is_array($item)) {
// This is a subtree and the index is the parent.
$this->matchPattern($item, $index);
// The index is actually an item to act on.
$item = $index;
$index = $i;
}
if (empty($index)) {
// This is the first item in the list and we don't know where to move
// it, so leave it where it is so it can be the reference for the next.
$i++;
}
else {
// We can move things.
$previous_item_key = $keys[$i - 1];
$previous_sibling = ($index) ? $pattern[$previous_item_key] : '';
$last_run = (++$i === $max_loops) ? TRUE : FALSE;
// No previous sibling means we are at the top of the list so needs to
// go above the entries.
// Most likely this test is redundant to the first item check above.
$below = (empty($previous_sibling)) ? FALSE : TRUE;
$this->moveMenuItem($item, $parent, $previous_sibling, $below, $last_run);
}
}
}
/**
* {@inheritdoc}
*/
......@@ -55,4 +89,60 @@ class MenuManipulator extends MenuManipulatorBase implements MenuManipulatorInte
return $highest_weight;
}
/**
* {@inheritdoc}
*/
public function moveMenuItem(
string $item_title,
string $parent_title = '',
string $sibling_title = '',
bool $below = TRUE,
bool $last_run = TRUE
): bool {
$moved = FALSE;
$highest_weight = $this->menuSeparate();
if (empty($sibling_title)) {
// There is no sibling so move it either to top or the bottom of menu.
$weight = ($below) ? $highest_weight + 2 : -2;
}
else {
// There is a sibling so use its weight.
$sibling_menu_item = $this->loadMenuItemByNameAndParentName($sibling_title, $parent_title);
$weight = $sibling_menu_item->getWeight() ?? NULL;
if (is_null($weight)) {
// We are flying blind because a sibling was not available so bail out.
$vars = [
'@title' => $item_title,
'@menu' => $this->menuName,
'@parent' => $parent_title,
'@sibling' => $sibling_title,
':link' => "/admin/structure/menu/manage/{$this->menuName}",
];
$message = "Menu @menu; '@title'was not moved. </br>";
$message .= "Reason: Sibling menu item '@sibling' under parent '@parent' was not found. </br>";
$message .= "Check menu <a href=\":link\">@menu</a> to see if it needs a menu item named '@sibling' under parent '@parent' and move '@title' manually.";
$this->logger->notice($message, $vars);
return $moved;
}
$weight = ($below) ? $weight + 1 : $weight - 1;
}
// Now move the item.
$menu_item = $this->loadMenuItemByNameAndParentName($item_title, $parent_title);
if ($menu_item->getWeight() !== $weight) {
// There is a change of weight, so save it.
$definition = $menu_item->getPluginDefinition();
$definition['weight'] = $weight;
$this->menuManager->updateDefinition($menu_item->getPluginId(), $definition);
$moved = TRUE;
$this->clearMenuTreeCache();
}
// Only separate the menu items on the last run, to keep from stacking
// the pre and post menuSeparate().
if ($last_run) {
$this->menuSeparate();
}
return $moved;
}
}
......@@ -38,6 +38,31 @@ interface MenuManipulatorInterface extends MenuManipulatorBaseInterface {
bool $below = TRUE
);
/**
* Rearrange items in a menu to match a pattern.
*
* @param array $pattern
* A pattern of parents and siblings.
*
* @codingStandardsIgnoreStart
* @code
* [
* 'parent1' => [
* subset_1_a,
* subset_1_b,
* subset_1_c,
* ]
* 'parent2' => [
* subset_2_a,
* subset_2_b,
* subset_2_c,
* ]
* ]
* @endcode
* @codingStandardsIgnoreEnd
*/
public function matchPattern(array $pattern): void;
/**
* Creates space between all menu item weights in a menu.
*
......@@ -46,4 +71,29 @@ interface MenuManipulatorInterface extends MenuManipulatorBaseInterface {
*/
public function menuSeparate(): int;
/**
* Move a menu item to a different location in the menu.
*
* @param string $item_title
* (required) The title of the menu item.
* @param string $parent_title
* The title of the parent to lookup.
* @param string $sibling_title
* The title of the nearest sibling.
* @param bool $below
* TRUE to place the new menu item below the sibling, FALSE to place above.
* @param bool $last_run
* A flag to make on last call to menuSeparate on the way out.
*
* @return bool
* TRUE if the item existed and was moved, FALSE if could not be found.
*/
public function moveMenuItem(
string $item_title,
string $parent_title = '',
string $sibling_title = '',
bool $below = TRUE,
bool $last_run = TRUE
): bool;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment