$item) {
if ($mid < 0 && ($item['type'] & MENU_MODIFIABLE_BY_ADMIN)) {
$new_mid = db_next_id('menu_mid');
if (isset($new_items[$item['pid']])) {
$new_pid = $new_items[$item['pid']]['mid'];
}
else {
$new_pid = $item['pid'];
}
// Fix parent IDs for menu items already added.
if ($item['children']) {
foreach ($item['children'] as $child) {
if (isset($new_items[$child])) {
$new_items[$child]['pid'] = $new_mid;
}
}
}
$new_items[$mid] = array('mid' => $new_mid, 'pid' => $new_pid, 'path' => $item['path'], 'title' => $item['title'], 'weight' => $item['weight'], 'type' => $item['type']);
}
}
foreach ($new_items as $item) {
db_query('INSERT INTO {menu} (mid, pid, path, title, weight, type) VALUES (%d, %d, \'%s\', \'%s\', %d, %d)', $item['mid'], $item['pid'], $item['path'], $item['title'], $item['weight'], $item['type']);
}
// Rebuild the menu to account for any changes.
_menu_build();
}
/** @} end of "menu" function group */
/**
* @addtogroup themeable
* @{
*/
/**
* Returns a rendered menu tree.
*/
function theme_menu_tree($pid = 1, $all = FALSE) {
$menu = menu_get_menu();
$output = '';
if (isset($menu['visible'][$pid]) && $menu['visible'][$pid]['children']) {
foreach ($menu['visible'][$pid]['children'] as $mid) {
$style = (count($menu['visible'][$mid]['children']) ? (menu_in_active_trail($mid) ? 'expanded' : 'collapsed') : 'leaf');
$output .= "
";
$output .= theme('menu_item', $mid);
if ($all || menu_in_active_trail($mid)) {
$output .= theme('menu_tree', $mid);
}
$output .= "\n";
}
if ($output != '') {
$output = "\n\n";
}
}
return $output;
}
/**
* Generate the HTML representing a given menu item ID.
*
* @param $mid
* The menu ID to render.
*/
function theme_menu_item($mid) {
$menu = menu_get_menu();
return l($menu['items'][$mid]['title'], $menu['items'][$mid]['path']);
}
/**
* Returns the rendered local tasks. The default implementation renders
* them as tabs.
*/
function theme_menu_local_tasks() {
$active = true;
if ($mid = menu_get_active_nontask_item()) {
$menu = menu_get_menu();
if ($children = $menu['items'][$mid]['children']) {
foreach ($menu['items'][$mid]['children'] as $cid) {
if (($menu['items'][$cid]['type'] & MENU_IS_LOCAL_TASK) && _menu_item_is_accessible($cid)) {
if (menu_in_active_trail($cid)) {
$tabs[] = theme('menu_local_task', $cid, TRUE);
$active = false;
}
else {
$tabs[] = theme('menu_local_task', $cid, FALSE);
}
}
}
if ($tabs) {
// We add a default view-tab for the parent:
$output = "\n";
$output .= theme('menu_local_task', $mid, $active);
$output .= implode($tabs);
$output .= "
\n";
$output .= theme('menu_local_subtasks', $mid);
}
}
}
return $output;
}
/**
* Generate the HTML representing a given menu item ID as a set of tabs.
*
* @param $mid
* The menu ID to render.
* @param $active
* Whether this tab or a subtab is the active menu item.
*/
function theme_menu_local_task($mid, $active) {
if ($active) {
return ''. theme('menu_item', $mid) ."\n";
}
else {
return ''. theme('menu_item', $mid) ."\n";
}
}
/**
* Generate the HTML representing the children of a given menu item ID
* as a set of tabs.
*
* @param $pid
* The menu ID of the parent item.
*/
function theme_menu_local_subtasks($pid) {
$menu = menu_get_menu();
$tabs = '';
if ($children = $menu['items'][$pid]['children']) {
foreach ($children as $cid) {
if (_menu_item_is_accessible($cid) && ($menu['items'][$cid]['type'] & MENU_IS_LOCAL_SUBTASK)) {
$tabs .= theme('menu_local_task', $cid, menu_in_active_trail($cid));
}
}
if ($tabs) {
return "\n";
}
}
}
/** @} End of addtogroup themeable */
/**
* Returns an array with the menu items that lead to the specified path.
*/
function _menu_get_trail($path) {
$menu = menu_get_menu();
$trail = array();
// Find the ID of the given path.
while ($path && !$menu['path index'][$path]) {
$path = substr($path, 0, strrpos($path, '/'));
}
$mid = $menu['path index'][$path];
// Follow the parents up the chain to get the trail.
while ($mid && $menu['items'][$mid]) {
array_unshift($trail, $mid);
$mid = $menu['items'][$mid]['pid'];
}
return $trail;
}
/**
* Comparator routine for use in sorting menu items.
*/
function _menu_sort($a, $b) {
$menu = menu_get_menu();
$a = &$menu['items'][$a];
$b = &$menu['items'][$b];
return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : ($a['title'] < $b['title'] ? -1 : 1));
}
/**
* Build the menu by querying both modules and the database.
*/
function _menu_build() {
global $_menu;
global $user;
// Start from a clean slate.
$_menu = array();
$_menu['path index'] = array();
// Set up items array, including default "Navigation" menu.
$_menu['items'] = array(
0 => array('type' => MENU_IS_ROOT),
1 => array('pid' => 0, 'title' => t('Navigation'), 'weight' => -50, 'access' => TRUE, 'type' => MENU_IS_ROOT | MENU_VISIBLE_IN_TREE)
);
// Build a sequential list of all menu items.
$menu_item_list = module_invoke_all('menu');
// Menu items not in the DB get temporary negative IDs.
$temp_mid = -1;
foreach ($menu_item_list as $item) {
if (!isset($item['type'])) {
$item['type'] = MENU_NORMAL_ITEM;
}
$mid = $temp_mid;
if (isset($_menu['path index'][$item['path']])) {
// Newer menu items overwrite older ones.
unset($_menu['items'][$_menu['path index'][$item['path']]]);
}
$_menu['items'][$mid] = $item;
$_menu['path index'][$item['path']] = $mid;
$temp_mid--;
}
// Now fetch items from the DB, reassigning menu IDs as needed.
if (module_exist('menu')) {
$result = db_query('SELECT * FROM {menu}');
while ($item = db_fetch_object($result)) {
// Don't display non-custom menu items if no module declared them.
if ($old_mid = $_menu['path index'][$item->path]) {
$_menu['items'][$item->mid] = $_menu['items'][$old_mid];
unset($_menu['items'][$old_mid]);
$_menu['path index'][$item->path] = $item->mid;
// If administrator has changed item position, reflect the change.
if ($item->type & MENU_MODIFIED_BY_ADMIN) {
$_menu['items'][$item->mid]['title'] = $item->title;
$_menu['items'][$item->mid]['pid'] = $item->pid;
$_menu['items'][$item->mid]['weight'] = $item->weight;
$_menu['items'][$item->mid]['type'] = $item->type;
}
}
// Next, add any custom items added by the administrator.
else if ($item->type & MENU_CREATED_BY_ADMIN) {
$_menu['items'][$item->mid] = array('pid' => $item->pid, 'path' => $item->path, 'title' => $item->title, 'access' => TRUE, 'weight' => $item->weight, 'type' => $item->type);
$_menu['path index'][$item->path] = $item->mid;
}
}
}
// Establish parent-child relationships.
foreach ($_menu['items'] as $mid => $item) {
if (!isset($item['pid'])) {
// Parent's location has not been customized, so figure it out using the path.
$parent = $item['path'];
do {
$parent = substr($parent, 0, strrpos($parent, '/'));
}
while ($parent && !$_menu['path index'][$parent]);
$pid = $parent ? $_menu['path index'][$parent] : 1;
$_menu['items'][$mid]['pid'] = $pid;
}
else {
$pid = $item['pid'];
}
// Don't make root a child of itself.
if ($mid) {
if (isset ($_menu['items'][$pid])) {
$_menu['items'][$pid]['children'][] = $mid;
}
else {
// If parent is missing, it is a menu item that used to be defined
// but is no longer. Default to a root-level "Navigation" menu item.
$_menu['items'][1]['children'][] = $mid;
}
}
}
// Prepare to display trees to the user as required.
_menu_build_visible_tree();
}
/**
* Determine whether the given menu item is accessible to the current user.
*
* Use this instead of just checking the "access" property of a menu item
* to properly handle items with fall-through semantics.
*/
function _menu_item_is_accessible($mid) {
$menu = menu_get_menu();
if (isset($menu['items'][$mid]['access'])) {
return $menu['items'][$mid]['access'];
}
// Follow the path up to find the actual callback.
$path = $menu['items'][$mid]['path'];
while ($path && (!$menu['path index'][$path] || !$menu['items'][$menu['path index'][$path]]['callback'])) {
$path = substr($path, 0, strrpos($path, '/'));
}
$callback_mid = $menu['path index'][$path];
return $menu['items'][$callback_mid]['access'];
}
/**
* Find all visible items in the menu tree, for ease in displaying to user.
*
* Since this is only for display, we only need title, path, and children
* for each item.
*/
function _menu_build_visible_tree($pid = 0) {
global $_menu;
if (isset($_menu['items'][$pid])) {
$parent = $_menu['items'][$pid];
$children = array();
if ($parent['children']) {
usort($parent['children'], '_menu_sort');
foreach ($parent['children'] as $mid) {
$children = array_merge($children, _menu_build_visible_tree($mid));
}
}
$visible = ($parent['type'] & MENU_VISIBLE_IN_TREE) ||
($parent['type'] & MENU_VISIBLE_IF_HAS_CHILDREN && count($children) > 0);
$allowed = _menu_item_is_accessible($pid);
if (($parent['type'] & MENU_IS_ROOT) || ($visible && $allowed)) {
$_menu['visible'][$pid] = array('title' => $parent['title'], 'path' => $parent['path'], 'children' => $children);
foreach ($children as $mid) {
$_menu['visible'][$mid]['pid'] = $pid;
}
return array($pid);
}
else {
return $children;
}
}
return array();
}
?>