menu_link_save

Versions
6 – 7
menu_link_save(&$item)

Save a menu link.

Parameters

$item An array representing a menu link item. The only mandatory keys are link_path and link_title. Possible keys are:

  • menu_name default is navigation
  • weight default is 0
  • expanded whether the item is expanded.
  • options An array of options, @see l for more.
  • mlid Set to an existing value, or 0 or NULL to insert a new link.
  • plid The mlid of the parent.
  • router_path The path of the relevant router item.

Return value

The mlid of the saved menu link, or FALSE if the menu link could not be saved.

Related topics

▾ 15 functions call menu_link_save()

book_admin_edit_submit in modules/book/book.admin.inc
Handle submission of the book administrative page form.
menu_edit_item_submit in modules/menu/menu.admin.inc
Process menu and menu item add/edit form submissions.
menu_edit_menu_submit in modules/menu/menu.admin.inc
Submit function for adding or editing a custom menu.
menu_enable in modules/menu/menu.module
Implement hook_enable().
menu_link_maintain in includes/menu.inc
Insert, update or delete an uncustomized menu link related to a module.
menu_node_save in modules/menu/menu.module
Helper for hook_node_insert() and hook_node_update().
menu_overview_form_submit in modules/menu/menu.admin.inc
Submit handler for the menu overview form.
menu_reset_item in modules/menu/menu.module
Reset a system-defined menu item.
shortcut_link_edit_submit in modules/shortcut/shortcut.admin.inc
Submit handler for the shortcut link editing form.
shortcut_set_customize_submit in modules/shortcut/shortcut.admin.inc
Submit handler for the shortcut set customization form.
shortcut_set_save in modules/shortcut/shortcut.module
Saves a shortcut set.
toolbar_install in modules/toolbar/toolbar.install
Implementation of hook_install().
_book_update_outline in modules/book/book.module
Common helper function to handles additions and updates to the book outline.
_menu_delete_item in includes/menu.inc
Helper function for menu_link_delete; deletes a single menu link.
_menu_navigation_links_rebuild in includes/menu.inc
Helper function to build menu links for the items in the menu router.

Code

includes/menu.inc, line 2544

<?php
function menu_link_save(&$item) {

  drupal_alter('menu_link', $item);

  // This is the easiest way to handle the unique internal path '<front>',
  // since a path marked as external does not need to match a router path.
  $item['external'] = (url_is_external($item['link_path'])  || $item['link_path'] == '<front>') ? 1 : 0;
  // Load defaults.
  $item += array(
    'menu_name' => 'navigation',
    'weight' => 0,
    'link_title' => '',
    'hidden' => 0,
    'has_children' => 0,
    'expanded' => 0,
    'options' => array(),
    'module' => 'menu',
    'customized' => 0,
    'updated' => 0,
  );
  $existing_item = FALSE;
  if (isset($item['mlid'])) {
    if ($existing_item = db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $item['mlid']))->fetchAssoc()) {
      $existing_item['options'] = unserialize($existing_item['options']);
    }
  }

  if (isset($item['plid'])) {
    if ($item['plid']) {
      $parent = db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $item['plid']))->fetchAssoc();
    }
    else {
      // Don't bother with the query - mlid can never equal zero..
      $parent = FALSE;
    }
  }
  else {
    $query = db_select('menu_links');
    // Only links derived from router items should have module == 'system', and
    // we want to find the parent even if it's in a different menu.
    if ($item['module'] == 'system') {
      $query->condition('module', 'system');
    }
    else {
      // If not derived from a router item, we respect the specified menu name.
      $query->condition('menu_name', $item['menu_name']);
    }

    // Find the parent - it must be unique.
    $parent_path = $item['link_path'];
    do {
      $parent = FALSE;
      $parent_path = substr($parent_path, 0, strrpos($parent_path, '/'));
      $new_query = clone $query;
      $new_query->condition('link_path', $parent_path);
      // Only valid if we get a unique result.
      if ($new_query->countQuery()->execute()->fetchField() == 1) {
        $parent = $new_query->fields('menu_links')->execute()->fetchAssoc();
      }
    } while ($parent === FALSE && $parent_path);
  }
  if ($parent !== FALSE) {
    $item['menu_name'] = $parent['menu_name'];
  }
  $menu_name = $item['menu_name'];
  // Menu callbacks need to be in the links table for breadcrumbs, but can't
  // be parents if they are generated directly from a router item.
  if (empty($parent['mlid']) || $parent['hidden'] < 0) {
    $item['plid'] =  0;
  }
  else {
    $item['plid'] = $parent['mlid'];
  }

  if (!$existing_item) {
    $item['mlid'] = db_insert('menu_links')
      ->fields(array(
        'menu_name' => $item['menu_name'],
        'plid' => $item['plid'],
        'link_path' => $item['link_path'],
        'hidden' => $item['hidden'],
        'external' => $item['external'],
        'has_children' => $item['has_children'],
        'expanded' => $item['expanded'],
        'weight' => $item['weight'],
        'module' => $item['module'],
        'link_title' => $item['link_title'],
        'options' => serialize($item['options']),
        'customized' => $item['customized'],
        'updated' => $item['updated'],
      ))
      ->execute();
  }

  if (!$item['plid']) {
    $item['p1'] = $item['mlid'];
    for ($i = 2; $i <= MENU_MAX_DEPTH; $i++) {
      $item["p$i"] = 0;
    }
    $item['depth'] = 1;
  }
  else {
    // Cannot add beyond the maximum depth.
    if ($item['has_children'] && $existing_item) {
      $limit = MENU_MAX_DEPTH - menu_link_children_relative_depth($existing_item) - 1;
    }
    else {
      $limit = MENU_MAX_DEPTH - 1;
    }
    if ($parent['depth'] > $limit) {
      return FALSE;
    }
    $item['depth'] = $parent['depth'] + 1;
    _menu_link_parents_set($item, $parent);
  }
  // Need to check both plid and menu_name, since plid can be 0 in any menu.
  if ($existing_item && ($item['plid'] != $existing_item['plid'] || $menu_name != $existing_item['menu_name'])) {
    _menu_link_move_children($item, $existing_item);
  }
  // Find the router_path.
  if (empty($item['router_path'])  || !$existing_item || ($existing_item['link_path'] != $item['link_path'])) {
    if ($item['external']) {
      $item['router_path'] = '';
    }
    else {
      // Find the router path which will serve this path.
      $item['parts'] = explode('/', $item['link_path'], MENU_MAX_PARTS);
      $item['router_path'] = _menu_find_router_path($item['link_path']);
    }
  }
  // If every value in $existing_item is the same in the $item, there is no
  // reason to run the update queries or clear the caches. We use
  // array_intersect_assoc() with the $item as the first parameter because
  // $item may have additional keys left over from building a router entry.
  // The intersect removes the extra keys, allowing a meaningful comparison.
  if (!$existing_item || (array_intersect_assoc($item, $existing_item)) != $existing_item) {
    db_update('menu_links')
      ->fields(array(
        'menu_name' => $item['menu_name'],
        'plid' => $item['plid'],
        'link_path' => $item['link_path'],
        'router_path' => $item['router_path'],
        'hidden' => $item['hidden'],
        'external' => $item['external'],
        'has_children' => $item['has_children'],
        'expanded' => $item['expanded'],
        'weight' => $item['weight'],
        'depth' => $item['depth'],
        'p1' => $item['p1'],
        'p2' => $item['p2'],
        'p3' => $item['p3'],
        'p4' => $item['p4'],
        'p5' => $item['p5'],
        'p6' => $item['p6'],
        'p7' => $item['p7'],
        'p8' => $item['p8'],
        'p9' => $item['p9'],
        'module' => $item['module'],
        'link_title' => $item['link_title'],
        'options' => serialize($item['options']),
        'customized' => $item['customized'],
      ))
      ->condition('mlid', $item['mlid'])
      ->execute();
    // Check the has_children status of the parent.
    _menu_update_parental_status($item);
    menu_cache_clear($menu_name);
    if ($existing_item && $menu_name != $existing_item['menu_name']) {
      menu_cache_clear($existing_item['menu_name']);
    }
    // Notify modules we have acted on a menu item.
    $hook = 'menu_link_insert';
    if ($existing_item) {
      $hook = 'menu_link_update';
    }
    module_invoke_all($hook, $item);
    // Now clear the cache.
    _menu_clear_page_cache();
  }
  return $item['mlid'];
}
?>
Login or register to post comments
 
 

All source code and documentation on this site is released under the terms of the GNU General Public License, version 2 and later. Drupal is a registered trademark of Dries Buytaert.