function menu_link_save

7.x menu.inc menu_link_save(&$item, $existing_item = array(), $parent_candidates = array())
6.x menu.inc 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

13 calls to menu_link_save()
book_admin_edit_submit in drupal-6.x/modules/book/book.admin.inc
Handle submission of the book administrative page form.
book_update_6000 in drupal-6.x/modules/book/book.install
Drupal 5.x to 6.x update.
menu_edit_item_submit in drupal-6.x/modules/menu/menu.admin.inc
Process menu and menu item add/edit form submissions.
menu_edit_menu_submit in drupal-6.x/modules/menu/menu.admin.inc
Submit function for adding or editing a custom menu.
menu_enable in drupal-6.x/modules/menu/menu.module
Implementation of hook_enable()

... See full list

File

drupal-6.x/includes/menu.inc, line 1904
API for the Drupal menu system.

Code

function menu_link_save(&$item) {

  // Get the router if it's already in memory. $menu will be NULL, unless this
  // is during a menu rebuild
  $menu = _menu_router_cache();
  drupal_alter('menu_link', $item, $menu);

  // 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'] = menu_path_is_external($item['link_path']) || $item['link_path'] == '<front>';
  // 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'])) {
    $existing_item = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $item['mlid']));
  }

  if (isset($item['plid'])) {
    $parent = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $item['plid']));
  }
  else {
    // Find the parent - it must be unique.
    $parent_path = $item['link_path'];
    $where = "WHERE link_path = '%s'";
    // 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') {
      $where .= " AND module = '%s'";
      $arg2 = 'system';
    }
    else {
      // If not derived from a router item, we respect the specified menu name.
      $where .= " AND menu_name = '%s'";
      $arg2 = $item['menu_name'];
    }
    do {
      $parent = FALSE;
      $parent_path = substr($parent_path, 0, strrpos($parent_path, '/'));
      $result = db_query("SELECT COUNT(*) FROM {menu_links} " . $where, $parent_path, $arg2);
      // Only valid if we get a unique result.
      if (db_result($result) == 1) {
        $parent = db_fetch_array(db_query("SELECT * FROM {menu_links} " . $where, $parent_path, $arg2));
      }
    } 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) {
    db_query("INSERT INTO {menu_links} (
       menu_name, plid, link_path,
      hidden, external, has_children,
      expanded, weight,
      module, link_title, options,
      customized, updated) VALUES (
      '%s', %d, '%s',
      %d, %d, %d,
      %d, %d,
      '%s', '%s', '%s', %d, %d)", 
    $item['menu_name'], $item['plid'], $item['link_path'], 
    $item['hidden'], $item['_external'], $item['has_children'], 
    $item['expanded'], $item['weight'], 
    $item['module'], $item['link_title'], serialize($item['options']), 
    $item['customized'], $item['updated']);
    $item['mlid'] = db_last_insert_id('menu_links', 'mlid');
  }

  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 callback. During the menu update we store empty paths to be
  // fixed later, so we skip this.
  if (!isset($_SESSION['system_update_6021']) && (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']);
    }
  }
  db_query("UPDATE {menu_links} SET menu_name = '%s', plid = %d, link_path = '%s',
    router_path = '%s', hidden = %d, external = %d, has_children = %d,
    expanded = %d, weight = %d, depth = %d,
    p1 = %d, p2 = %d, p3 = %d, p4 = %d, p5 = %d, p6 = %d, p7 = %d, p8 = %d, p9 = %d,
    module = '%s', link_title = '%s', options = '%s', customized = %d WHERE mlid = %d", 
  $item['menu_name'], $item['plid'], $item['link_path'], 
  $item['router_path'], $item['hidden'], $item['_external'], $item['has_children'], 
  $item['expanded'], $item['weight'], $item['depth'], 
  $item['p1'], $item['p2'], $item['p3'], $item['p4'], $item['p5'], $item['p6'], $item['p7'], $item['p8'], $item['p9'], 
  $item['module'], $item['link_title'], serialize($item['options']), $item['customized'], $item['mlid']);
  // 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']);
  }

  _menu_clear_page_cache();
  return $item['mlid'];
}