1 menu.inc _menu_navigation_links_rebuild($menu)

Builds menu links for the items in the menu router.

Related topics

File

core/includes/menu.inc, line 3001
API for the Backdrop menu system.

Code

function _menu_navigation_links_rebuild($menu) {
  // Add normal and suggested items as links.
  $menu_links = array();
  $default_menu_link_paths = array();
  foreach ($menu as $path => $item) {
    if ($item['_visible']) {
      $menu_links[$path] = $item;
      $default_menu_link_paths[] = $path;
      $sort[$path] = $item['_number_parts'];
    }
  }
  if ($menu_links) {
    // Keep an array of processed menu links, to allow menu_link_save() to
    // check this for parents instead of querying the database.
    $parent_candidates = array();
    // Make sure no child comes before its parent.
    array_multisort($sort, SORT_NUMERIC, $menu_links);

    foreach ($menu_links as $key => $item) {
      $existing_item = db_select('menu_links')
        ->fields('menu_links')
        ->condition('link_path', $item['path'])
        ->condition('module', 'system')
        ->execute()->fetchAssoc();
      if ($existing_item) {
        $item['mlid'] = $existing_item['mlid'];
        // A change in hook_menu may move the link to a different menu
        if (empty($item['menu_name']) || ($item['menu_name'] == $existing_item['menu_name'])) {
          $item['menu_name'] = $existing_item['menu_name'];
          $item['plid'] = $existing_item['plid'];
        }
        else {
          // It moved to a new menu. Let menu_link_save() try to find a new
          // parent based on the path.
          unset($item['plid']);
        }
        $item['has_children'] = $existing_item['has_children'];
        $item['updated'] = $existing_item['updated'];
      }
      if ($existing_item && $existing_item['customized']) {
        $parent_candidates[$existing_item['mlid']] = $existing_item;
      }
      else {
        $item = _menu_link_build($item);
        menu_link_save($item, $existing_item, $parent_candidates);
        $parent_candidates[$item['mlid']] = $item;
        unset($menu_links[$key]);
      }
    }
  }
  $paths = array_keys($menu);
  // Updated and customized items whose router paths are gone need new ones.
  $result = db_select('menu_links', NULL, array('fetch' => PDO::FETCH_ASSOC))
    ->fields('menu_links', array(
      'link_path',
      'mlid',
      'router_path',
      'updated',
    ))
    ->condition(db_or()
      ->condition('updated', 1)
      ->condition(db_and()
        ->condition('router_path', $paths, 'NOT IN')
        ->condition('external', 0)
        ->condition('customized', 1)
        )
      )
    ->execute();
  foreach ($result as $item) {
    $router_path = _menu_find_router_path($item['link_path']);
    if (!empty($router_path) && ($router_path != $item['router_path'] || $item['updated'])) {
      // If the router path and the link path matches, it's surely a working
      // item, so we clear the updated flag.
      $updated = $item['updated'] && $router_path != $item['link_path'];
      db_update('menu_links')
        ->fields(array(
          'router_path' => $router_path,
          'updated' => (int) $updated,
        ))
        ->condition('mlid', $item['mlid'])
        ->execute();
    }
  }
  // Find any item that is no longer visible.
  $result = db_select('menu_links')
    ->fields('menu_links')
    ->condition('router_path', $default_menu_link_paths, 'NOT IN')
    ->condition('external', 0)
    ->condition('updated', 0)
    ->condition('customized', 0)
    ->orderBy('depth', 'DESC')
    ->execute();
  // Remove all such items. Starting from those with the greatest depth will
  // minimize the amount of re-parenting done by menu_link_delete().
  foreach ($result as $item) {
    _menu_delete_item($item, TRUE);
  }
}