diff --git a/includes/menu.inc b/includes/menu.inc
index 05ecac0..db2329e 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -994,16 +994,19 @@ function menu_get_object($type = 'node', $position = 1, $path = NULL) {
  *
  * @param $menu_name
  *   The name of the menu.
+ * @param $skip_hidden
+ *   (optional) Improve performance by skipping hidden menu links in tree
+ *   see _menu_tree_check_access
  *
  * @return
  *   A structured array representing the specified menu on the current page, to
  *   be rendered by drupal_render().
  */
-function menu_tree($menu_name) {
+function menu_tree($menu_name, $skip_hidden = FALSE) {
   $menu_output = &drupal_static(__FUNCTION__, array());
 
   if (!isset($menu_output[$menu_name])) {
-    $tree = menu_tree_page_data($menu_name);
+    $tree = menu_tree_page_data($menu_name, NULL, FALSE, $skip_hidden);
     $menu_output[$menu_name] = menu_tree_output($tree);
   }
   return $menu_output[$menu_name];
@@ -1108,11 +1111,13 @@ function menu_tree_output($tree) {
  *   Optional maximum depth of links to retrieve. Typically useful if only one
  *   or two levels of a sub tree are needed in conjunction with a non-NULL
  *   $link, in which case $max_depth should be greater than $link['depth'].
+ * @param (optional) $skip_hidden
+ *   skip hidden menu items, see _menu_tree_check_access
  *
  * @return
  *   An tree of menu links in an array, in the order they should be rendered.
  */
-function menu_tree_all_data($menu_name, $link = NULL, $max_depth = NULL) {
+function menu_tree_all_data($menu_name, $link = NULL, $max_depth = NULL, $skip_hidden = FALSE) {
   $tree = &drupal_static(__FUNCTION__, array());
 
   // Use $mlid as a flag for whether the data being loaded is for the whole tree.
@@ -1154,7 +1159,7 @@ function menu_tree_all_data($menu_name, $link = NULL, $max_depth = NULL) {
 
     // Build the tree using the parameters; the resulting tree will be cached
     // by _menu_build_tree()).
-    $tree[$cid] = menu_build_tree($menu_name, $tree_parameters);
+    $tree[$cid] = menu_build_tree($menu_name, $tree_parameters, $skip_hidden);
   }
 
   return $tree[$cid];
@@ -1213,6 +1218,9 @@ function menu_tree_get_path($menu_name) {
  *   (optional) Whether to only return the links in the active trail (TRUE)
  *   instead of all links on every level of the menu link tree (FALSE). Defaults
  *   to FALSE. Internally used for breadcrumbs only.
+ * @param $skip_hidden
+ *   (optional) Improve performance by skipping hidden menu links in tree
+ *   see _menu_tree_check_access
  *
  * @return
  *   An array of menu links, in the order they should be rendered. The array
@@ -1221,7 +1229,7 @@ function menu_tree_get_path($menu_name) {
  *   submenu below the link if there is one, and it is a subtree that has the
  *   same structure described for the top-level array.
  */
-function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail = FALSE) {
+function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail = FALSE, $skip_hidden = FALSE) {
   $tree = &drupal_static(__FUNCTION__, array());
 
   // Check if the active trail has been overridden for this menu tree.
@@ -1325,7 +1333,7 @@ function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail =
 
       // Build the tree using the parameters; the resulting tree will be cached
       // by _menu_build_tree().
-      $tree[$cid] = menu_build_tree($menu_name, $tree_parameters);
+      $tree[$cid] = menu_build_tree($menu_name, $tree_parameters, $skip_hidden);
     }
     return $tree[$cid];
   }
@@ -1354,15 +1362,18 @@ function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail =
  *   - max_depth: The maximum depth of menu links in the resulting tree.
  *   - conditions: An associative array of custom database select query
  *     condition key/value pairs; see _menu_build_tree() for the actual query.
+ * @param $skip_hidden
+ *   (optional) Improve performance by skipping hidden menu links in tree
+ *   see _menu_tree_check_access
  *
  * @return
  *   A fully built menu tree.
  */
-function menu_build_tree($menu_name, array $parameters = array()) {
+function menu_build_tree($menu_name, array $parameters = array(), $skip_hidden = FALSE) {
   // Build the menu tree.
   $data = _menu_build_tree($menu_name, $parameters);
   // Check access for the current user to each item in the tree.
-  menu_tree_check_access($data['tree'], $data['node_links']);
+  menu_tree_check_access($data['tree'], $data['node_links'], $skip_hidden);
   return $data['tree'];
 }
 
@@ -1493,8 +1504,9 @@ function menu_tree_collect_node_links(&$tree, &$node_links) {
  * @param $node_links
  *   A collection of node link references generated from $tree by
  *   menu_tree_collect_node_links().
+ * @param $skip_hidden (optional) for better performance skip hidden menu links
  */
-function menu_tree_check_access(&$tree, $node_links = array()) {
+function menu_tree_check_access(&$tree, $node_links = array(), $skip_hidden = FALSE) {
   if ($node_links && (user_access('access content') || user_access('bypass node access'))) {
     $nids = array_keys($node_links);
     $select = db_select('node', 'n');
@@ -1509,20 +1521,28 @@ function menu_tree_check_access(&$tree, $node_links = array()) {
       }
     }
   }
-  _menu_tree_check_access($tree);
+  _menu_tree_check_access($tree, $skip_hidden);
 }
 
 /**
  * Sorts the menu tree and recursively checks access for each item.
+ *
  */
-function _menu_tree_check_access(&$tree) {
+function _menu_tree_check_access(&$tree, $skip_hidden = FALSE) {
   $new_tree = array();
   foreach ($tree as $key => $v) {
     $item = &$tree[$key]['link'];
+    // Do not load hidden menu items if not in active breadcrumb trail and
+    // user can't administer the menu.
+    if ($skip_hidden) {
+      if (!empty($item['hidden']) && empty($item['in_active_trail']) && !user_access('administer menu')) {
+        continue;
+      }
+    }
     _menu_link_translate($item);
     if ($item['access'] || ($item['in_active_trail'] && strpos($item['href'], '%') !== FALSE)) {
       if ($tree[$key]['below']) {
-        _menu_tree_check_access($tree[$key]['below']);
+        _menu_tree_check_access($tree[$key]['below'], $skip_hidden);
       }
       // The weights are made a uniform 5 digits by adding 50000 as an offset.
       // After _menu_link_translate(), $item['title'] has the localized link title.
@@ -1810,23 +1830,29 @@ function menu_list_system_menus() {
 
 /**
  * Returns an array of links to be rendered as the Main menu.
+ * @param $skip_hidden
+ *   (optional) Improve performance by skipping hidden menu links in tree
+ *   see _menu_tree_check_access
  */
-function menu_main_menu() {
-  return menu_navigation_links(variable_get('menu_main_links_source', 'main-menu'));
+function menu_main_menu($skip_hidden = FALSE) {
+  return menu_navigation_links(variable_get('menu_main_links_source', 'main-menu'), $skip_hidden);
 }
 
 /**
  * Returns an array of links to be rendered as the Secondary links.
+ * @param $skip_hidden
+ *   (optional) Improve performance by skipping hidden menu links in tree
+ *   see _menu_tree_check_access
  */
-function menu_secondary_menu() {
+function menu_secondary_menu($skip_hidden = FALSE) {
 
   // If the secondary menu source is set as the primary menu, we display the
   // second level of the primary menu.
   if (variable_get('menu_secondary_links_source', 'user-menu') == variable_get('menu_main_links_source', 'main-menu')) {
-    return menu_navigation_links(variable_get('menu_main_links_source', 'main-menu'), 1);
+    return menu_navigation_links(variable_get('menu_main_links_source', 'main-menu'), 1, $skip_hidden);
   }
   else {
-    return menu_navigation_links(variable_get('menu_secondary_links_source', 'user-menu'), 0);
+    return menu_navigation_links(variable_get('menu_secondary_links_source', 'user-menu'), 0, $skip_hidden);
   }
 }
 
@@ -1837,18 +1863,21 @@ function menu_secondary_menu() {
  *   The name of the menu.
  * @param $level
  *   Optional, the depth of the menu to be returned.
+ * @param $skip_hidden
+ *   (optional) Improve performance by skipping hidden menu links in tree
+ *   see _menu_tree_check_access
  *
  * @return
  *   An array of links of the specified menu and level.
  */
-function menu_navigation_links($menu_name, $level = 0) {
+function menu_navigation_links($menu_name, $level = 0, $skip_hidden = FALSE) {
   // Don't even bother querying the menu table if no menu is specified.
   if (empty($menu_name)) {
     return array();
   }
 
   // Get the menu hierarchy for the current page.
-  $tree = menu_tree_page_data($menu_name, $level + 1);
+  $tree = menu_tree_page_data($menu_name, $level + 1, FALSE, $skip_hidden);
 
   // Go down the active trail until the right level is reached.
   while ($level-- > 0 && $tree) {
@@ -2370,11 +2399,14 @@ function menu_set_active_item($path) {
  *   Menu trail to set; the value is saved in a static variable and can be
  *   retrieved by menu_get_active_trail(). The format of this array should be
  *   the same as the return value of menu_get_active_trail().
+ * @param $skip_hidden
+ *   (optional) Improve performance by skipping hidden menu links in tree
+ *   see _menu_tree_check_access
  *
  * @return
  *   The active trail. See menu_get_active_trail() for details.
  */
-function menu_set_active_trail($new_trail = NULL) {
+function menu_set_active_trail($new_trail = NULL, $skip_hidden = FALSE) {
   $trail = &drupal_static(__FUNCTION__);
 
   if (isset($new_trail)) {
@@ -2400,7 +2432,7 @@ function menu_set_active_trail($new_trail = NULL) {
       // Pass TRUE for $only_active_trail to make menu_tree_page_data() build
       // a stripped down menu tree containing the active trail only, in case
       // the given menu has not been built in this request yet.
-      $tree = menu_tree_page_data($preferred_link['menu_name'], NULL, TRUE);
+      $tree = menu_tree_page_data($preferred_link['menu_name'], NULL, TRUE, $skip_hidden);
       list($key, $curr) = each($tree);
     }
     // There is no link for the current path.
@@ -2877,7 +2909,7 @@ function _menu_link_build($item) {
 /**
  * Builds menu links for the items in the menu router.
  */
-function _menu_navigation_links_rebuild($menu) {
+function _menu_navigation_links_rebuild($menu, $skip_hidden = FALSE) {
   // Add normal and suggested items as links.
   $menu_links = array();
   foreach ($menu as $path => $item) {
