Skip to content
Snippets Groups Projects
Select Git revision
  • 7bdcba172030b6c4aedf3e00514af1a857a04593
  • 11.x default protected
  • 11.2.x protected
  • 10.6.x protected
  • 10.5.x protected
  • 11.1.x protected
  • 10.4.x protected
  • 11.0.x protected
  • 10.3.x protected
  • 7.x protected
  • 10.2.x protected
  • 10.1.x protected
  • 9.5.x protected
  • 10.0.x protected
  • 9.4.x protected
  • 9.3.x protected
  • 9.2.x protected
  • 9.1.x protected
  • 8.9.x protected
  • 9.0.x protected
  • 8.8.x protected
  • 10.5.1 protected
  • 11.2.2 protected
  • 11.2.1 protected
  • 11.2.0 protected
  • 10.5.0 protected
  • 11.2.0-rc2 protected
  • 10.5.0-rc1 protected
  • 11.2.0-rc1 protected
  • 10.4.8 protected
  • 11.1.8 protected
  • 10.5.0-beta1 protected
  • 11.2.0-beta1 protected
  • 11.2.0-alpha1 protected
  • 10.4.7 protected
  • 11.1.7 protected
  • 10.4.6 protected
  • 11.1.6 protected
  • 10.3.14 protected
  • 10.4.5 protected
  • 11.0.13 protected
41 results

menu.module

Blame
  • Dries Buytaert's avatar
    - Patch #19739 by Uwe: corrected many typo's in the documentation and code comments
    Dries Buytaert authored
    7bdcba17
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    menu.module 16.89 KiB
    <?php
    // $Id$
    
    /**
     * @file
     * Allows administrators to customize the site navigation menu.
     */
    
    /**
     * Implementation of hook_menu().
     */
    function menu_menu($may_cache) {
      $items = array();
    
      if ($may_cache) {
        $items[] = array('path' => 'admin/menu', 'title' => t('menus'),
          'callback' => 'menu_overview',
          'access' => user_access('administer menu'));
        $items[] = array('path' => 'admin/menu/item/edit', 'title' => t('edit menu item'),
          'callback' => 'menu_edit_item',
          'access' => user_access('administer menu'),
          'type' => MENU_CALLBACK);
        $items[] = array('path' => 'admin/menu/item/reset', 'title' => t('reset menu item'),
          'callback' => 'menu_reset_item',
          'access' => user_access('administer menu'),
          'type' => MENU_CALLBACK);
        $items[] = array('path' => 'admin/menu/item/disable', 'title' => t('disable menu item'),
          'callback' => 'menu_disable_item',
          'access' => user_access('administer menu'),
          'type' => MENU_CALLBACK);
        $items[] = array('path' => 'admin/menu/item/delete', 'title' => t('delete menu item'),
          'callback' => 'menu_delete_item',
          'access' => user_access('administer menu'),
          'type' => MENU_CALLBACK);
    
        $items[] = array('path' => 'admin/menu/list', 'title' => t('list'),
          'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
        $items[] = array('path' => 'admin/menu/menu/add', 'title' => t('add menu'),
          'callback' => 'menu_add_menu',
          'access' => user_access('administer menu'),
          'type' => MENU_LOCAL_TASK);
        $items[] = array('path' => 'admin/menu/item/add', 'title' => t('add menu item'),
          'callback' => 'menu_edit_item',
          'access' => user_access('administer menu'),
          'type' => MENU_LOCAL_TASK);
        $items[] = array('path' => 'admin/menu/reset', 'title' => t('reset menus'),
          'callback' => 'menu_reset',
          'access' => user_access('administer menu'),
          'type' => MENU_LOCAL_TASK);
      }
    
      return $items;
    }
    
    /**
     * Implementation of hook_help().
     */
    function menu_help($section) {
      switch ($section) {
        case 'admin/modules#description':
          return t('Allows administrators to customize the site navigation menu.');
        case 'admin/menu':
          return t('<p>Select an operation from the list to move, change, or delete a menu item.</p>');
        case 'admin/menu/menu/add':
          return t('<p>Enter the name for your new menu. Remember to enable the newly created block in the %blocks administration page.</p>', array('%blocks' => l(t('blocks'), 'admin/block')));
        case 'admin/menu/item/add':
          return t('<p>Enter the title, path, position and the weight for your new menu item.</p>');
      }
    }
    
    /**
     * Implementation of hook_block().
     */
    function menu_block($op = 'list', $delta = 0) {
      $menu = menu_get_menu();
    
      if ($op == 'list') {
        $blocks = array();
        foreach ($menu['items'][0]['children'] as $mid) {
          // Default "Navigation" block is handled by user.module.
          if ($mid != 1) {
            $blocks[$mid]['info'] = $menu['items'][$mid]['title'];
          }
        }
        return $blocks;
      }
      else if ($op == 'view') {
        $data['subject'] = $menu['items'][$delta]['title'];
        $data['content'] = '<div class="menu">'. theme('menu_tree', $delta) .'</div>' ;
        return $data;
      }
    }
    
    /**
     * Implementation of hook_perm().
     */
    function menu_perm() {
      return array('administer menu');
    }
    
    /**
     * Menu callback; present the main menu management page.
     */
    function menu_overview() {
      menu_rebuild();
    
      print theme('page', menu_overview_tree());
    }
    
    /**
     * Menu callback; clear the database, resetting the menu to factory defaults.
     */
    function menu_reset() {
      $op = $_POST['op'];
      switch ($op) {
        case t('Reset all'):
          db_query('DELETE FROM {menu}');
          drupal_set_message(t('All menu items reset.'));
          drupal_goto('admin/menu');
          break;
        default:
          $output = theme('confirm',
                          t('Are you sure you want to reset all menu items to their default settings?'),
                          'admin/menu',
                          t('Any custom additions or changes to the menu will be lost.'),
                          t('Reset all'));
          print theme('page', $output);
      }
    }
    
    /**
     * Menu callback; handle the adding of a new menu.
     */
    function menu_add_menu() {
      $op = $_POST['op'];
      $edit = $_POST['edit'];
      $output = '';
    
      switch ($op) {
        case t('Submit'):
          menu_edit_item_validate($edit);
          if (!form_get_errors()) {
            menu_edit_item_save($edit);
            drupal_goto('admin/menu');
          }
          // Fall through.
        default:
          $edit['pid'] = 0;
          $edit['type'] = MENU_CUSTOM_MENU;
          $output .= menu_edit_item_form($edit);
      }
    
      print theme('page', $output);
    }
    
    /**
     * Menu callback; reset a single modified item.
     */
    function menu_reset_item($mid) {
      $op = $_POST['op'];
      switch ($op) {
        case t('Reset'):
          db_query('DELETE FROM {menu} WHERE mid = %d', $mid);
          drupal_set_message(t('Menu item reset.'));
          drupal_goto('admin/menu');
          break;
        default:
          $title = db_result(db_query('SELECT title FROM {menu} WHERE mid = %d', $mid));
          $output = theme('confirm',
                          t('Are you sure you want to reset the item %item to its default values?', array('%item' => theme('placeholder', $title))),
                          'admin/menu',
                          t('Any customizations will be lost. This action cannot be undone.'),
                          t('Reset'));
          print theme('page', $output);
      }
    }
    
    /**
     * Menu callback; delete a single custom item.
     */
    function menu_delete_item($mid) {
      $op = $_POST['op'];
      $result = db_query('SELECT type, title FROM {menu} WHERE mid = %d', $mid);
      $menu = db_fetch_object($result);
      if (!$menu) {
        drupal_goto('admin/menu');
      }
      switch ($op) {
        case t('Delete'):
          db_query('DELETE FROM {menu} WHERE mid = %d', $mid);
          if ($menu->type & MENU_IS_ROOT) {
            drupal_set_message(t('Menu deleted.'));
          }
          else {
            drupal_set_message(t('Menu item deleted.'));
          }
          drupal_goto('admin/menu');
          break;
        default:
          if ($menu->type & MENU_IS_ROOT) {
            $message = t('Are you sure you want to delete the menu %item?', array('%item' => theme('placeholder', $menu->title)));
          }
          else {
            $message = t('Are you sure you want to delete the custom menu item %item?', array('%item' => theme('placeholder', $menu->title)));
          }
          $output = theme('confirm', $message, 'admin/menu', t('This action cannot be undone.'), t('Delete'));
          print theme('page', $output);
      }
    }
    
    /**
     * Menu callback; hide a menu item.
     */
    function menu_disable_item($mid) {
      $menu = menu_get_menu();
      $type = $menu['items'][$mid]['type'];
      $type &= ~MENU_VISIBLE_IN_TREE;
      $type &= ~MENU_VISIBLE_IN_BREADCRUMB;
      $type |= MENU_MODIFIED_BY_ADMIN;
      db_query('UPDATE {menu} SET type = %d WHERE mid = %d', $type, $mid);
      drupal_set_message(t('Menu item disabled.'));
      drupal_goto('admin/menu');
    }
    
    /**
     * Menu callback; dispatch to the appropriate menu item edit function.
     */
    function menu_edit_item($mid = 0) {
      $op = $_POST['op'];
      $edit = $_POST['edit'];
    
      $output = '';
    
      switch ($op) {
        case t('Submit'):
          menu_edit_item_validate($edit);
          if (!form_get_errors()) {
            menu_edit_item_save($edit);
            drupal_goto('admin/menu');
          }
          $output .= menu_edit_item_form($edit);
          break;
        default:
          if ($mid > 0) {
            $item = db_fetch_object(db_query('SELECT * FROM {menu} WHERE mid = %d', $mid));
    
            $edit['mid'] = $item->mid;
            $edit['pid'] = $item->pid;
            $edit['path'] = $item->path;
            $edit['title'] = $item->title;
            $edit['description'] = $item->description;
            $edit['weight'] = $item->weight;
            $edit['type'] = $item->type;
          }
          else {
            $edit['mid'] = 0; // In case a negative ID was passed in.
            $edit['pid'] = 1; // default to "Navigation" menu.
            $edit['type'] = MENU_CUSTOM_ITEM;
          }
          $output .= menu_edit_item_form($edit);
      }
    
      print theme('page', $output);
    }
    
    /**
     * Present the menu item editing form.
     */
    function menu_edit_item_form($edit) {
      $menu = menu_get_menu();
    
      $form .= form_textfield(t('Title'), 'title', $edit['title'], 60, 128, t('The name to display for this link.'), NULL, TRUE);
    
      if ($edit['pid'] == 0) {
        // Display a limited set of fields for menus (not items).
        $form .= form_hidden('path', '');
        $form .= form_hidden('pid', 0);
        $form .= form_hidden('weight', 0);
      }
      else {
        $form .= form_textfield(t('Description'), 'description', $edit['description'], 60, 128, t('The description displayed when hovering over a menu item.'));
    
        $path_description = t('The Drupal path this menu item links to.');
        if (isset($edit['path']) && array_key_exists($edit['path'], $menu['path index']) && $menu['path index'][$edit['path']] != $edit['mid']) {
          $old_mid = $menu['path index'][$edit['path']];
          $old_item = $menu['items'][$old_mid];
          $path_description .= "\n". t('Since a menu item "%old" already exists for "%path", this menu item is shortcut to that location.', array('%old' => l($old_item['title'], 'admin/menu/item/edit/'. $old_mid), '%path' => $edit['path']));
        }
    
        if ($edit['type'] & MENU_CREATED_BY_ADMIN) {
          $form .= form_textfield(t('Path'), 'path', $edit['path'], 60, 128, $path_description, NULL, TRUE);
        }
        else {
          $form .= form_item(t('Path'), l($edit['path'], $edit['path']));
          $form .= form_hidden('path', $edit['path']);
        }
    
        $form .= form_checkbox(t('Expanded'), 'expanded', 1, ($edit['type'] & MENU_EXPANDED), t('If selected and this menu item has children, the menu will always appear expanded.'));
    
        // Generate a list of possible parents (not including this item or descendants).
        $options = menu_parent_options($edit['mid']);
        $form .= form_select(t('Parent item'), 'pid', $edit['pid'], $options);
    
        $form .= form_weight(t('Weight'), 'weight', $edit['weight'], 10, t('Optional. In the menu, the heavier items will sink and the lighter items will be positioned nearer the top.'));
      }
    
      $form .= form_submit(t('Submit'));
    
      $form .= form_hidden('mid', $edit['mid']);
    
      // Always enable menu items (but not menus) when editing them.
      if (!($edit['type'] & MENU_IS_ROOT)) {
        $edit['type'] |= MENU_VISIBLE_IN_TREE | MENU_VISIBLE_IN_BREADCRUMB;
      }
    
      $form .= form_hidden('type', $edit['type']);
    
      return form($form);
    }
    
    /**
     * Confirm that an edited menu item has fields properly filled in.
     */
    function menu_edit_item_validate($edit) {
      if (empty($edit['title'])) {
        form_set_error('title', t('You must specify a title.'));
      }
    
      if ($edit['pid'] != 0) {
        if (empty($edit['path'])) {
          form_set_error('path', t('You must specify a path.'));
        }
      }
    }
    
    /**
     * Save changes to a menu item into the database.
     */
    function menu_edit_item_save($edit) {
      $menu = menu_get_menu();
    
      if ($edit['expanded']) {
        $edit['type'] |= MENU_EXPANDED;
      }
      else {
        $edit['type'] &= ~MENU_EXPANDED;
      }
    
      if ($edit['mid']) {
        db_query("UPDATE {menu} SET pid = %d, path = '%s', title = '%s', description = '%s', weight = %d, type = %d WHERE mid = %d", $edit['pid'], $edit['path'], $edit['title'], $edit['description'], $edit['weight'], $edit['type'] | MENU_MODIFIED_BY_ADMIN, $edit['mid']);
        drupal_set_message(t('Updated menu item %title.', array('%title' => theme('placeholder', $edit['title']))));
      }
      else {
        $mid = db_next_id('{menu}_mid');
        db_query("INSERT INTO {menu} (mid, pid, path, title, description, weight, type) VALUES (%d, %d, '%s', '%s', '%s', %d, %d)", $mid, $edit['pid'], $edit['path'], $edit['title'], $edit['description'], $edit['weight'], $edit['type'] | MENU_MODIFIED_BY_ADMIN);
        drupal_set_message(t('Created new menu item %title.', array('%title' => theme('placeholder', $edit['title']))));
        if (array_key_exists($edit['path'], $menu['path index'])) {
          $old_mid = $menu['path index'][$edit['path']];
          $old_item = $menu['items'][$old_mid];
          drupal_set_message(t('Since a menu item %old already exists for %path, this new menu item was created as a shortcut to that location.', array('%old' => l(theme('placeholder', $old_item['title']), 'admin/menu/item/edit/'. $old_mid, array(), NULL, NULL, FALSE, TRUE), '%path' => theme('placeholder', $edit['path']))));
        }
      }
    }
    
    /**
     * Present the menu tree, rendered along with links to edit menu items.
     */
    function menu_overview_tree() {
      $menu = menu_get_menu();
      $header = array(t('Menu item'), t('Expanded'), array('data' => t('Operations'), 'colspan' => '3'));
      $output = '';
    
      foreach ($menu['items'][0]['children'] as $mid) {
        $operations = array();
        if ($menu['items'][$mid]['type'] & MENU_MODIFIABLE_BY_ADMIN) {
          $operations[] = l(t('edit'), 'admin/menu/item/edit/'. $mid);
        }
        if ($menu['items'][$mid]['type'] & MENU_CREATED_BY_ADMIN) {
          $operations[] = l(t('delete'), 'admin/menu/item/delete/'. $mid);
        }
        $table = theme('item_list', $operations);
        $table .= theme('table', $header, menu_overview_tree_rows($mid));
        $output .= theme('box', $menu['items'][$mid]['title'], $table);
      }
      return $output;
    }
    
    function menu_overview_tree_rows($pid = 0, $depth = 0) {
      $menu = menu_get_menu();
    
      $rows = array();
    
      if (isset($menu['items'][$pid]) && $menu['items'][$pid]['children']) {
    
        usort($menu['items'][$pid]['children'], '_menu_sort');
        foreach ($menu['items'][$pid]['children'] as $mid) {
          // Populate the title field.
          $title = '';
          if ($pid == 0) {
            // Top-level items are menu names, and don't have an associated path.
            $title .= $menu['items'][$mid]['title'];
          }
          else {
            $title .= l($menu['items'][$mid]['title'], $menu['items'][$mid]['path']);
          }
          if ($depth > 0) {
            $title = '-&nbsp;'. $title;
          }
          for ($i = 1; $i < $depth; $i++) {
            $title = '&nbsp;&nbsp;'. $title;
          }
    
          // Populate the operations field.
          $operations = array();
          if (!($menu['items'][$mid]['type'] & MENU_MODIFIABLE_BY_ADMIN)) {
            $operations[] = array('data' => t('locked'), 'colspan' => '3', 'align' => 'center');
          }
          else {
            if ($menu['items'][$mid]['type'] & MENU_VISIBLE_IN_TREE) {
              $operations[] = array('data' => l(t('edit'), 'admin/menu/item/edit/'. $mid));
              if ($menu['items'][$mid]['type'] & MENU_IS_ROOT) {
                // Disabling entire menus is done from block admin page.
                $operations[] = array('data' => '');
              }
              else {
                $operations[] = array('data' => l(t('disable'), 'admin/menu/item/disable/'. $mid));
              }
            }
            else {
              $operations[] = array('data' => '');
              $operations[] = array('data' => l(t('enable'), 'admin/menu/item/edit/'. $mid));
            }
    
            if ($menu['items'][$mid]['type'] & MENU_CREATED_BY_ADMIN) {
              $operations[] = array('data' => l(t('delete'), 'admin/menu/item/delete/'. $mid));
            }
            else if ($menu['items'][$mid]['type'] & MENU_MODIFIED_BY_ADMIN) {
              $operations[] = array('data' => l(t('reset'), 'admin/menu/item/reset/'. $mid));
            }
            else {
              $operations[] = array('data' => '');
            }
          }
    
          // Call out disabled items.
          if ($menu['items'][$mid]['type'] & MENU_VISIBLE_IN_TREE) {
            $class = 'menu-enabled';
          }
          else {
            $title .= ' ('. t('disabled') .')';
            $class = 'menu-disabled';
          }
    
          if ($menu['items'][$mid]['type'] & (MENU_MODIFIABLE_BY_ADMIN | MENU_VISIBLE_IN_TREE)) {
            $row = array(array('data' => $title, 'class' => $class), array('data' => ($menu['items'][$mid]['children'] ? (($menu['items'][$mid]['type'] & MENU_EXPANDED) ? t('Yes') : t('No')) : ''), 'class' => $class));
            foreach ($operations as $operation) {
              $operation['class'] = $class;
              $row[] = $operation;
            }
            $rows[] = $row;
            $rows = array_merge($rows, menu_overview_tree_rows($mid, $depth + 1));
          }
          else {
            // Skip items that are hidden and locked; admins will never care about them.
            $rows = array_merge($rows, menu_overview_tree_rows($mid, $depth));
          }
        }
    
      }
    
      return $rows;
    }
    
    /**
     * Return a list of menu items that are valid possible parents for the
     * given menu item.
     */
    function menu_parent_options($mid, $pid = 0, $depth = 0) {
      $menu = menu_get_menu();
    
      $options = array();
    
      if (isset($menu['items'][$pid]) && $menu['items'][$pid]['children']) {
        usort($menu['items'][$pid]['children'], '_menu_sort');
        foreach ($menu['items'][$pid]['children'] as $child) {
          if ($child != $mid) {
            if ($child > 0 && ($menu['items'][$child]['type'] & (MENU_MODIFIABLE_BY_ADMIN | MENU_IS_ROOT))) {
              $title = ' '. $menu['items'][$child]['title'];
              for ($i = 0; $i < $depth; $i++) {
                $title = '--'. $title;
              }
              if (!($menu['items'][$child]['type'] & MENU_VISIBLE_IN_TREE)) {
                $title .= ' ('. t('disabled') .')';
              }
              $options[$child] = $title;
            }
            $options += menu_parent_options($mid, $child, $depth + 1);
          }
        }
      }
    
      return $options;
    }
    
    ?>