Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
This code was built for a project which included:
- the ability to create menus
- the ability to have duplicated menus
- having a sidebar that contains the current selected menu
By adding node/1?b=1 at the end of the menus that were duplicated, a simple operation could verify if they menu was selected or not.
Fixing duplication requires that everytime a menu is saved, we go through the menu structure again to fix the problematic menus appending ?b=X at the end. You can either push a button in the admin interface or just modify them, as it hook on menu_link_alter.
<?php
function duplicated_menus_menu() {
$items['admin/settings/duplicated_menus'] = array(
'title' => 'Duplicated menus admin page',
'page callback' => 'drupal_get_form',
'page arguments' => array('duplicated_menus_admin_form'),
'access arguments' => array('access content'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
function duplicated_menus_admin_form() {
$form = array();
$form['description'] = array(
'#type' => 'markup',
'#value' => t('This button force reloading the primary menus to add proper menu numbering allowing duplicates to have their own predefinite paths'),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Reload primary links'),
);
return $form;
}
function duplicated_menus_admin_form_submit($form, &$form_state) {
_duplicated_menus_rebuild_primary();
}
function _duplicated_menus_get_dupes($level, $current, $list, $known_paths) {
$ids = 0;
# drupal_set_message('recursion_called, level = ' . count($current));
if(!is_array($level)) {
// drupal_set_message(print_r($level,1));
} else {
foreach($level as $weighted_mlid => $item) {
# drupal_set_message($weighted_mlid .' rec dupes');
//drupal_set_message(print_r($current,1) . ', list is ' . print_r($list, 1));
$subcurrent = $current;
// This gets the dupes, regardless of their previous treatment as dupe
$the_path = preg_replace('/\?b=(\d)+/', '', $item['link']['link_path']);
array_push($subcurrent, $ids);
if (!in_array($the_path, array_keys($known_paths))) {
$known_paths[$the_path] = array($subcurrent, $item['link']['mlid']);
} else {
# drupal_set_message(print_r($list,1));
if (in_array($the_path, array_keys($list))) {
# drupal_set_message('exists');
$list[$the_path][] = array($subcurrent, $item['link']['mlid']);
# drupal_set_message('after:' . print_r($list[$the_path], 1));
} else {
$werd = menu_link_load($known_paths[$the_path][1]);
# drupal_set_message('weights: ' . $werd['weight'] .'and'. $item['link']['weight'] . ' and '. $item['link']['plid'] .' plids '.$werd['plid']);
# drupal_set_message(print_r($item['link'],1));
if($werd['plid'] == $item['link']['plid']) {
if ($werd['weight'] > $item['link']['weight']) {
$list[$the_path] = array(1 => $known_paths[$the_path], 0 => array($subcurrent, $item['link']['mlid']));
} else {
$list[$the_path] = array(0 => $known_paths[$the_path], 1 => array($subcurrent, $item['link']['mlid']));
}
} else {
$list[$the_path] = array(0 => $known_paths[$the_path], 1 => array($subcurrent, $item['link']['mlid']));
}
#drupal_set_message('built the first 2,' . print_r($list[$the_path], 1) . ' known_path being ' . print_r($known_paths[$the_path], 1) . ' and weighted_mlids being' . $weighted_mlid);
}
}
if (is_array($item['below']) && count($item['below'])) {
list($l, $kp) = _duplicated_menus_get_dupes($item['below'], $subcurrent, $list, $known_paths);
$list = array_merge($list, $l);
$known_paths += $kp;
}
$ids++;
}
}
# drupal_set_message('out of rec, going back to = ' . (count($current) - 1));
return array($list, $known_paths);
}
function _duplicated_menus_rebuild_primary() {
menu_cache_clear_all();
$menu = menu_tree_all_data('primary-links');
$fe = array();
list($list, $known_paths) = _duplicated_menus_get_dupes($menu, array(), $fe, array());
# drupal_set_message(print_r($list,1));
foreach ($list as $path => $item) {
$items = array();
foreach($item as $count => $val) {
list($address, $mlid) = $val;
$items[] = $mlid;
$obj = menu_link_load($mlid);
$obj['link_path'] = preg_replace('/\?b=(\d)+/', '', $obj['link_path']);
unset($obj['options']['attributes']['query']);
if ($obj['options']['query'] != "b=$count" || $obj['localized_options']['query'] != "b=$count") {
$obj['options']['query'] = "b=$count";
$obj['localized_options']['query'] = "b=$count";
$obj['do_not_rebuild'] = 1;
# drupal_set_message('menu: ' . $obj['mlid'] . ' got altered, with count='. $count . ' opt ='. $obj['options']['query']);
# drupal_set_message('<pre>' . print_r($obj,1));
if (!menu_link_save($obj)) {
drupal_set_message(t('There was an error saving the menu link.'), 'error');
}
}
# $obj2 = menu_link_load($obj['mlid']);
# while ($obj2['options']['query'] != $obj['options']['query']) {
# menu_link_save($obj);
# $obj2 = menu_link_load($obj['mlid']);
# }
}
#drupal_set_message('path: ' . $path . ' contained ' . print_r($items,1));
}
# drupal_set_message('done rebuilding...');
}
function duplicated_menus_menu_link_alter(&$item, $menu) {
if (!$item['do_not_rebuild']) {
# drupal_set_message("menu_link_alter got called");
$item['do_not_rebuild'] = 1;
// this sounds like: it will duplicate and fuck everything up
// but because it is saved an mlid will be set, its totally fine
// we need to save to alter the weight
# drupal_set_message('in MLA' . $item['weight'] . $item['link_title']);
if (!menu_link_save($item)) {
drupal_set_message(t('There was an error saving the menu link.'), 'error');
}
_duplicated_menus_rebuild_primary();
# drupal_set_message('saved now rebuilding');
$item2 = menu_link_load($item['mlid']);
$item['options'] = $item2['options'];
}
}
function _duplicated_menus_recurse_menu_setintrail($menu, $deselectors, $val) {
$key = array_keys($menu);
if (is_array($deselectors) && !empty($deselectors)) {
$num = array_shift($deselectors);
}
$menu[$key[$num]]['link']['in_active_trail'] = $val;
if (is_array($menu[$key[$num]]['below']) && count($menu[$key[$num]]['below']) > 0 && count($deselectors)) {
$menu[$key[$num]]['below'] = _duplicated_menus_recurse_menu_setintrail($menu[$key[$num]]['below'], $deselectors, $val);
}
return $menu;
}
function duplicated_menus_block($op = 'list', $delta = 0) {
if ($op == 'list') {
$blocks[0] = array(
'info' => t('Current menu'),
'weight' => 0,
'status' => 1,
'region' => 'left',
);
return $blocks;
} else if ($op == 'view') {
switch ($delta) {
case 0:
// Your module will need to define this function to render the block.
$block = array(
'subject' => t(''),
'content' => duplicated_menus_current_menus(),
);
break;
}
}
return $block;
}
function duplicated_menus_current_menus() {
$menus = menu_tree_page_data('primary-links');
if (arg(0) != 'admin') {
$fe = array();
list($redirects, $known_paths) = _duplicated_menus_get_dupes($menu, array(), $fe, array());
foreach(array_keys($redirects) as $item) {
$parts = explode('/', $item);
$i = 0;
$is_it_it = 1;
foreach($parts as $part) {
if ($part != arg($i) && $part != '*') {
$is_it_it = 0;
}
$i++;
}
if ($is_it_it && isset($_GET['b'])) { // if its a redirection (b != 0) we just set in trail ,0 to unset, then same thing, 1 to set the new value
$menus = _duplicated_menus_recurse_menu_setintrail($menus, $redirects[$item][0][0], 0);
$menus = _duplicated_menus_recurse_menu_setintrail($menus, $redirects[$item][$_GET['b']][0], 1);
} elseif($is_it_it && (count($redirects[$item][0]) == 0)) { // otherwise, we just set
$menus = _duplicated_menus_recurse_menu_setintrail($menus, $redirects[$item][0][0], 1);
}
}
foreach($menus as $systitle => $data) {
if ($data['link']['in_active_trail']) {
$menu = $data;
// FALSE && FALSE == TRUE
if (isset($data['below']) && is_array($data['below'])) {
unset($menu['below']) ;
$output = '<div id="primary-links-sub">' . menu_tree_output(array("blah"=>$menu) + $data['below']) . '</div>';
} else {
$output = '<div id="primary-links-sub">' . menu_tree_output(array("blah"=>$menu)) . '</div>';
}
return $output;
}
}
}
}
function duplicated_menus_fix_menus($menus) {
$keys = array_keys($menus);
$menu = menu_tree_all_data('primary-links');
$fe = array();
list($redirects, $known_paths) = _duplicated_menus_get_dupes($menu, array(), $fe, array());
if (isset($_GET['b'])) {
foreach(array_keys($redirects) as $item) {
$parts = explode('/', $item);
$i = 0;
$is_it_it = 1;
foreach($parts as $part) {
if ($part != arg($i) && $part != '*') {
$is_it_it = 0;
}
$i++;
}
if ($is_it_it) { // this is so self explanatory it shouldn't need comment
$menus = _duplicated_menus_recurse_menu_setintrail($menus, $redirects[$item][0][0], 0);
$menus = _duplicated_menus_recurse_menu_setintrail($menus, $redirects[$item][$_GET['b']][0], 1);
}
}
}
return $menus;
}
?>
and duplicated_menu.info :
; $Id: calendar.info,v 1.8 2008/04/23 23:42:53 karens Exp $
name = duplicated_menus
description = Allow duplicated menus
core = 6.x