Same name and namespace in other branches
  1. 4.6.x includes/menu.inc \_menu_build()
  2. 5.x includes/menu.inc \_menu_build()

Build the menu by querying both modules and the database.

1 call to _menu_build()
menu_rebuild in includes/menu.inc
Populate the database representation of the menu.

File

includes/menu.inc, line 1018
API for the Drupal menu system.

Code

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(
      'path' => '',
      'title' => '',
      'type' => MENU_IS_ROOT,
    ),
    1 => array(
      'pid' => 0,
      'path' => '',
      'title' => t('Navigation'),
      'weight' => -50,
      'access' => TRUE,
      'type' => MENU_IS_ROOT | MENU_VISIBLE_IN_TREE,
    ),
  );
  $_menu['callbacks'] = array();

  // Build a sequential list of all menu items.
  $menu_item_list = module_invoke_all('menu', TRUE);

  // Menu items not in the DB get temporary negative IDs.
  $temp_mid = -1;
  foreach ($menu_item_list as $item) {
    if (!isset($item['path'])) {
      $item['path'] = '';
    }
    if (!isset($item['type'])) {
      $item['type'] = MENU_NORMAL_ITEM;
    }
    if (!isset($item['weight'])) {
      $item['weight'] = 0;
    }
    $mid = $temp_mid;
    if (isset($_menu['path index'][$item['path']])) {

      // Newer menu items overwrite older ones.
      unset($_menu['items'][$_menu['path index'][$item['path']]]);
    }
    if (isset($item['callback'])) {
      $_menu['callbacks'][$item['path']] = array(
        'callback' => $item['callback'],
      );
      if (isset($item['callback arguments'])) {
        $_menu['callbacks'][$item['path']]['callback arguments'] = $item['callback arguments'];
      }
    }
    unset($item['callback']);
    unset($item['callback arguments']);
    $_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(db_rewrite_sql('SELECT m.mid, m.* FROM {menu} m ORDER BY m.mid ASC', 'm', 'mid'));
    while ($item = db_fetch_object($result)) {

      // Handle URL aliases if entered in menu administration.
      if (!isset($_menu['path index'][$item->path])) {
        $item->path = drupal_get_normal_path($item->path);
      }
      if (isset($_menu['path index'][$item->path])) {

        // The path is already declared.
        $old_mid = $_menu['path index'][$item->path];
        if ($old_mid < 0) {

          // It had a temporary ID, so use a permanent one.
          $_menu['items'][$item->mid] = $_menu['items'][$old_mid];
          unset($_menu['items'][$old_mid]);
          $_menu['path index'][$item->path] = $item->mid;
        }
        else {

          // It has a permanent ID. Only replace with non-custom menu items.
          if ($item->type & MENU_CREATED_BY_ADMIN) {
            $_menu['items'][$item->mid] = array(
              'path' => $item->path,
            );
          }
          else {

            // Leave the old item around as a shortcut to this one.
            $_menu['items'][$item->mid] = $_menu['items'][$old_mid];
            $_menu['path index'][$item->path] = $item->mid;
          }
        }
      }
      else {

        // The path was not declared, so this is a custom item or an orphaned one.
        if ($item->type & MENU_CREATED_BY_ADMIN) {
          $_menu['items'][$item->mid] = array(
            'path' => $item->path,
          );
          if (!empty($item->path)) {
            $_menu['path index'][$item->path] = $item->mid;
          }
        }
      }

      // If the administrator has changed the item, reflect the change.
      if ($item->type & MENU_MODIFIED_BY_ADMIN) {
        $_menu['items'][$item->mid]['title'] = $item->title;
        $_menu['items'][$item->mid]['description'] = $item->description;
        $_menu['items'][$item->mid]['pid'] = $item->pid;
        $_menu['items'][$item->mid]['weight'] = $item->weight;
        $_menu['items'][$item->mid]['type'] = $item->type;
      }
    }
  }

  // Associate parent and child menu items.
  _menu_find_parents($_menu['items']);

  // Prepare to display trees to the user as required.
  _menu_build_visible_tree();
}