diff --git a/includes/menu.inc b/includes/menu.inc
index 05ecac0..d127df6 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -1108,11 +1108,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 +1156,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];
@@ -1325,7 +1327,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 +1356,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 +1498,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 +1515,26 @@ 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 && !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.
