=== modified file 'includes/bootstrap.inc'
--- includes/bootstrap.inc	2010-07-26 03:05:36 +0000
+++ includes/bootstrap.inc	2010-08-15 06:43:35 +0000
@@ -1741,7 +1741,7 @@ function drupal_get_title() {
 
   // During a bootstrap, menu.inc is not included and thus we cannot provide a title.
   if (!isset($title) && function_exists('menu_get_active_title')) {
-    $title = check_plain(menu_get_active_title());
+    $title = menu_get_active_title();
   }
 
   return $title;

=== modified file 'includes/entity.inc'
--- includes/entity.inc	2010-07-26 02:51:46 +0000
+++ includes/entity.inc	2010-08-15 06:27:32 +0000
@@ -405,6 +405,10 @@ class EntityFieldQueryException extends 
  * specified or if the query has field conditions or sorts that are stored in
  * different field storage engines. However, this logic can be overridden in
  * hook_entity_query().
+ *
+ * Also note that this query does not automatically respect entity access
+ * restrictions. Node access control is performed by the SQL storage engine but
+ * other storage engines might not do this.
  */
 class EntityFieldQuery {
   /**
@@ -516,6 +520,24 @@ class EntityFieldQuery {
   public $age = FIELD_LOAD_CURRENT;
 
   /**
+   * A list of the tags added to this query.
+   *
+   * @var array
+   *
+   * @see EntityFieldQuery::addTag()
+   */
+  public $tags = array();
+
+  /**
+   * A list of metadata added to this query.
+   *
+   * @var array
+   *
+   * @see EntityFieldQuery::addMetaData()
+   */
+  public $metaData = array();
+
+  /**
    * The ordered results.
    *
    * @var array
@@ -817,6 +839,52 @@ class EntityFieldQuery {
   }
 
   /**
+   * Adds a tag to the query.
+   *
+   * Tags are strings that mark a query so that hook_query_alter() and
+   * hook_query_TAG_alter() implementations may decide if they wish to alter
+   * the query. A query may have any number of tags, and they must be valid PHP
+   * identifiers (composed of letters, numbers, and underscores). For example,
+   * queries involving nodes that will be displayed for a user need to add the
+   * tag 'node_access', so that the node module can add access restrictions to
+   * the query.
+   *
+   * If an entity field query has tags, it must also have an entity type
+   * specified, because the alter hook will need the entity base table.
+   *
+   * @param string $tag
+   *   The tag to add.
+   *
+   * @return EntityFieldQuery
+   *   The called object.
+   */
+  public function addTag($tag) {
+    $this->tags[$tag] = $tag;
+    return $this;
+  }
+
+  /**
+   * Adds additional metadata to the query.
+   *
+   * Sometimes a query may need to provide additional contextual data for the
+   * alter hook. The alter hook implementations may then use that information
+   * to decide if and how to take action.
+   *
+   * @param $key
+   *   The unique identifier for this piece of metadata. Must be a string that
+   *   follows the same rules as any other PHP identifier.
+   * @param $object
+   *   The additional data to add to the query. May be any valid PHP variable.
+   *
+   * @return EntityFieldQuery
+   *   The called object.
+   */
+  public function addMetaData($key, $object) {
+    $this->metaData[$key] = $object;
+    return $this;
+  }
+
+  /**
    * Executes the query.
    *
    * After executing the query, $this->orderedResults will contain a list of
@@ -971,7 +1039,7 @@ class EntityFieldQuery {
   /**
    * Finishes the query.
    *
-   * Adds the range and returns the requested list.
+   * Adds tags, metaData, range  and returns the requested list or count.
    *
    * @param SelectQuery $select_query
    *   A SelectQuery which has entity_type, entity_id, revision_id and bundle
@@ -983,6 +1051,13 @@ class EntityFieldQuery {
    *   See EntityFieldQuery::execute().
    */
   function finishQuery($select_query, $id_key = 'entity_id') {
+    foreach ($this->tags as $tag) {
+      $select_query->addTag($tag);
+    }
+    foreach ($this->metaData as $key => $object) {
+      $select_query->addMetaData($key, $object);
+    }
+    $select_query->addMetaData('entity_field_query', $this);
     if ($this->range) {
       $select_query->range($this->range['start'], $this->range['length']);
     }

=== modified file 'includes/menu.inc'
--- includes/menu.inc	2010-08-05 07:56:50 +0000
+++ includes/menu.inc	2010-08-15 06:46:39 +0000
@@ -658,15 +658,15 @@ function _menu_item_localize(&$item, $ma
       else {
         $item['title'] = call_user_func_array($callback, menu_unserialize($item['title_arguments'], $map));
       }
-      // Avoid calling check_plain again on l() function.
-      if ($callback == 'check_plain') {
-        $item['localized_options']['html'] = TRUE;
-      }
     }
   }
   elseif ($link_translate) {
     $item['title'] = $item['link_title'];
   }
+  // Avoid calling check_plain again on l() function.
+  if ($callback == 'check_plain' || $item['title_output'] == PASS_THROUGH) {
+    $item['localized_options']['html'] = TRUE;
+  }
 
   // Translate description, see the motivation above.
   if (!empty($item['description'])) {
@@ -1240,6 +1240,7 @@ function _menu_build_tree($menu_name, ar
       'title',
       'title_callback',
       'title_arguments',
+      'title_output',
       'theme_callback',
       'theme_arguments',
       'type',
@@ -2115,7 +2116,7 @@ function menu_set_active_trail($new_trai
   }
   elseif (!isset($trail)) {
     $trail = array();
-    $trail[] = array('title' => t('Home'), 'href' => '<front>', 'localized_options' => array(), 'type' => 0);
+    $trail[] = array('title' => t('Home'), 'href' => '<front>', 'localized_options' => array(), 'type' => 0, 'title_output' => CHECK_PLAIN);
     $item = menu_get_item();
 
     // Check whether the current item is a local task (displayed as a tab).
@@ -2230,7 +2231,7 @@ function menu_get_active_title() {
 
   foreach (array_reverse($active_trail) as $item) {
     if (!(bool) ($item['type'] & MENU_IS_LOCAL_TASK)) {
-      return $item['title'];
+      return $item['title_output'] == PASS_THROUGH ? $item['title'] : check_plain($item['title']);
     }
   }
 }
@@ -3262,6 +3263,7 @@ function _menu_router_build($callbacks) 
       'block callback' => '',
       'title arguments' => array(),
       'title callback' => 't',
+      'title output' => CHECK_PLAIN,
       'theme arguments' => array(),
       'theme callback' => '',
       'description' => '',
@@ -3316,6 +3318,7 @@ function _menu_router_save($menu, $masks
       'title',
       'title_callback',
       'title_arguments',
+      'title_output',
       'theme_callback',
       'theme_arguments',
       'type',
@@ -3347,6 +3350,7 @@ function _menu_router_save($menu, $masks
       'title' => $item['title'],
       'title_callback' => $item['title callback'],
       'title_arguments' => ($item['title arguments'] ? serialize($item['title arguments']) : ''),
+      'title_output' => $item['title output'],
       'theme_callback' => $item['theme callback'],
       'theme_arguments' => serialize($item['theme arguments']),
       'type' => $item['type'],

=== modified file 'modules/book/book.module'
--- modules/book/book.module	2010-07-30 02:47:27 +0000
+++ modules/book/book.module	2010-08-15 06:47:51 +0000
@@ -1279,7 +1279,7 @@ function book_menu_subtree_data($link) {
       $query->join('menu_router', 'm', 'm.path = ml.router_path');
       $query->join('book', 'b', 'ml.mlid = b.mlid');
       $query->fields('b');
-      $query->fields('m', array('load_functions', 'to_arg_functions', 'access_callback', 'access_arguments', 'page_callback', 'page_arguments', 'delivery_callback', 'title', 'title_callback', 'title_arguments', 'type'));
+      $query->fields('m', array('load_functions', 'to_arg_functions', 'access_callback', 'access_arguments', 'page_callback', 'page_arguments', 'delivery_callback', 'title', 'title_callback', 'title_arguments', 'title_output', 'type'));
       $query->fields('ml');
       $query->condition('menu_name', $link['menu_name']);
       for ($i = 1; $i <= MENU_MAX_DEPTH && $link["p$i"]; ++$i) {

=== modified file 'modules/field/modules/field_sql_storage/field_sql_storage.module'
--- modules/field/modules/field_sql_storage/field_sql_storage.module	2010-08-01 19:49:35 +0000
+++ modules/field/modules/field_sql_storage/field_sql_storage.module	2010-08-15 06:26:49 +0000
@@ -502,6 +502,8 @@ function field_sql_storage_field_storage
     }
     else {
       $select_query = db_select($tablename, $table_alias);
+      $select_query->addTag('entity_field_access');
+      $select_query->addMetaData('base_table', $tablename);
       $select_query->fields($table_alias, array('entity_id', 'revision_id', 'bundle'));
       // As only a numeric ID is stored instead of the entity type add the
       // field_config_entity_type table to resolve the etid to a more readable
@@ -547,6 +549,7 @@ function field_sql_storage_field_storage
   if (isset($query->deleted)) {
     $select_query->condition("$field_base_table.deleted", (int) $query->deleted);
   }
+
   if ($query->propertyConditions || $query->propertyOrder) {
     if (empty($query->entityConditions['entity_type']['value'])) {
       throw new EntityFieldQueryException('Property conditions and orders must have an entity type defined.');

=== modified file 'modules/menu/menu.admin.inc'
--- modules/menu/menu.admin.inc	2010-08-01 23:33:18 +0000
+++ modules/menu/menu.admin.inc	2010-08-15 06:48:33 +0000
@@ -51,7 +51,7 @@ function menu_overview_form($form, &$for
   global $menu_admin;
   $form['#attached']['css'] = array(drupal_get_path('module', 'menu') . '/menu.css');
   $sql = "
-    SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.delivery_callback, m.title, m.title_callback, m.title_arguments, m.type, m.description, ml.*
+    SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.delivery_callback, m.title, m.title_callback, m.title_arguments, m.title_output, m.type, m.description, ml.*
     FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path
     WHERE ml.menu_name = :menu
     ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC";

=== modified file 'modules/node/node.module'
--- modules/node/node.module	2010-08-11 14:21:38 +0000
+++ modules/node/node.module	2010-08-15 06:26:49 +0000
@@ -2767,7 +2767,6 @@ function node_access($op, $node, $accoun
     $rights[$account->uid][$cid][$op] = TRUE;
     return TRUE;
   }
-
   if (!user_access('access content', $account)) {
     $rights[$account->uid][$cid][$op] = FALSE;
     return FALSE;
@@ -3009,6 +3008,33 @@ function node_access_view_all_nodes() {
  * 'update' and 'delete').
  */
 function node_query_node_access_alter(QueryAlterableInterface $query) {
+  _node_query_node_access_alter($query, 'node', 'node');
+}
+
+/**
+ * Implements hook_query_TAG_alter().
+ *
+ * This function implements the same functionality as
+ * node_query_node_access_alter() for the SQL field storage engine. Node access
+ * conditions are added for field values belonging to nodes only.
+ */
+function node_query_entity_field_access_alter(QueryAlterableInterface $query) {
+  _node_query_node_access_alter($query, $query->getMetaData('base_table'), 'entity');
+}
+
+/**
+ * Helper for node access functions.
+ *
+ * @param $query
+ *   The query to add conditions to.
+ * @param $base_table
+ *   The table holding node ids.
+ * @param $type
+ *   Either 'node' or 'entity' depending on what sort of query it is. See
+ *   node_query_node_access_alter() and node_query_entity_field_access_alter()
+ *   for more.
+ */
+function _node_query_node_access_alter($query, $base_table, $type) {
   global $user;
 
   // Read meta-data from query, if provided.
@@ -3037,12 +3063,24 @@ function node_query_node_access_alter(Qu
 
   $tables = $query->getTables();
   $grants = node_access_grants($op, $account);
+  // Entities can't add the node access conditions directly (see below for
+  // more) so collect them in a separate AND-condition.
+  $condition = $type == 'node' ? $query : db_and();
   foreach ($tables as $nalias => $tableinfo) {
     $table = $tableinfo['table'];
-    if (!($table instanceof SelectQueryInterface) && $table == 'node') {
+    if (!($table instanceof SelectQueryInterface) && $table == $base_table) {
+
+      // The node_access table has the access grants for any given node so JOIN
+      // it to the table containing the nid which can be either the node
+      // table or a field value table.
+      if ($type == 'node') {
+        $access_alias = $query->join('node_access', 'na', '%alias.nid = ' . $nalias . '.nid');
+      }
+      else {
+        $access_alias = $query->leftJoin('node_access', 'na', '%alias.nid = ' . $nalias . '.entity_id');
+        $base_alias = $nalias;
+      }
 
-      // The node_access table has the access grants for any given node.
-      $access_alias = $query->join('node_access', 'na', '%alias.nid = ' . $nalias . '.nid');
       $or = db_or();
       // If any grant exists for the specified user, then user has access
       // to the node for the specified operation.
@@ -3056,12 +3094,24 @@ function node_query_node_access_alter(Qu
       }
 
       if (count($or->conditions())) {
-        $query->condition($or);
+        $condition->condition($or);
       }
 
-      $query->condition($access_alias . '.grant_' . $op, 1, '>=');
+      $condition->condition($access_alias . '.grant_' . $op, 1, '>=');
     }
   }
+
+  if ($type == 'entity' && count($condition->conditions())) {
+    $or = db_or();
+    $etid = variable_get('field_sql_storage_node_etid');
+    // All these rules are only for field values belonging to nodes.
+    $condition->condition("$base_alias.etid", $etid);
+    $or->condition($condition);
+    // If the field value belongs to a non-node entity type then anything goes.
+    $or->condition("$base_alias.etid", $etid, '<>');
+    // Add the compiled set of rules to the query.
+    $query->condition($or);
+  }
 }
 
 /**

=== modified file 'modules/node/node.test'
--- modules/node/node.test	2010-08-08 13:02:37 +0000
+++ modules/node/node.test	2010-08-15 06:27:00 +0000
@@ -1692,6 +1692,68 @@ class NodeQueryAlter extends DrupalWebTe
   }
 }
 
+
+/**
+ * Tests node_query_entity_field_access_alter().
+ */
+class NodeEntityFieldQueryAlter extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Node entity query alter',
+      'description' => 'Test that node access entity queries are properly altered by the node module.',
+      'group' => 'Node',
+    );
+  }
+
+  /**
+   * User with permission to view content.
+   */
+  protected $accessUser;
+
+  /**
+   * User without permission to view content.
+   */
+  protected $noAccessUser;
+
+  function setUp() {
+    parent::setUp('node_access_test');
+    node_access_rebuild();
+    $settings = array('language' => LANGUAGE_NONE);
+    for ($i = 0; $i < 4; $i++) {
+      $body = array(
+        'value' => 'A' . $this->randomName(32),
+        'format' => filter_default_format(),
+      );
+      $settings['body'][LANGUAGE_NONE][0] = $body;
+      $this->drupalCreateNode($settings);
+    }
+
+    // Create user with simple node access permission.
+    $this->accessUser = $this->drupalCreateUser(array('access content', 'node test view'));
+    $this->noAccessUser = $this->drupalCreateUser(array('access content'));
+  }
+
+  /**
+   * Tests that node access permissions are followed.
+   */
+  function testNodeQueryAlterWithUI() {
+    // Verify that a user with access permission can see at least one node.
+
+    $this->drupalLogin($this->accessUser);
+    $this->drupalGet('node_access_entity_test_page');
+    $this->assertText('Yes, 4 nodes', "4 nodes were found for access user");
+    $this->assertNoText('Exception', "No database exception");
+
+    // Verify that a user with no access permission cannot see nodes.
+
+    $this->drupalLogin($this->noAccessUser);
+    $this->drupalGet('node_access_entity_test_page');
+    $this->assertText('No nodes', "No nodes were found for no access user");
+    $this->assertNoText('Exception', "No database exception");
+  }
+}
+
 /**
  * Test node token replacement in strings.
  */

=== modified file 'modules/node/tests/node_access_test.module'
--- modules/node/tests/node_access_test.module	2010-02-15 19:00:30 +0000
+++ modules/node/tests/node_access_test.module	2010-08-15 06:27:00 +0000
@@ -58,6 +58,12 @@ function node_access_test_menu() {
     'access arguments' => array('access content'),
     'type' => MENU_SUGGESTED_ITEM,
   );
+  $items['node_access_entity_test_page'] = array(
+    'title' => 'Node access test',
+    'page callback' => 'node_access_entity_test_page',
+    'access arguments' => array('access content'),
+    'type' => MENU_SUGGESTED_ITEM,
+  );
   return $items;
 }
 
@@ -100,3 +106,37 @@ function node_access_test_page() {
 
   return $output;
 }
+
+/**
+ * Page callback for node access entity test page.
+ *
+ * Page should say "No nodes" if there are no nodes, and "Yes, # nodes" (with
+ * the number filled in) if there were nodes the user could access. Also, the
+ * database query is shown, and a list of the node IDs, for debugging purposes.
+ * And if there is a query exception, the page says "Exception" and gives the
+ * error.
+ */
+function node_access_entity_test_page() {
+  $output = '';
+  try {
+    $query = new EntityFieldQuery;
+    $result = $query->fieldCondition('body', 'value', 'A', 'STARTS_WITH')->execute();
+    if (!empty($result['node'])) {
+      $output .= '<p>Yes, ' . count($result['node']) . ' nodes</p>';
+      $output .= '<ul>';
+      foreach ($result['node'] as $nid => $v) {
+        $output .= '<li>' . $nid . '</li>';
+      }
+      $output .= '</ul>';
+    }
+    else {
+      $output .= '<p>No nodes</p>';
+    }
+  }
+  catch (Exception $e) {
+    $output = '<p>Exception</p>';
+    $output .= '<p>' . $e->getMessage() . '</p>';
+  }
+
+  return $output;
+}

=== modified file 'modules/simpletest/tests/menu.test'
--- modules/simpletest/tests/menu.test	2010-08-08 19:35:48 +0000
+++ modules/simpletest/tests/menu.test	2010-08-15 06:49:17 +0000
@@ -35,6 +35,15 @@ class MenuRouterTestCase extends DrupalW
   }
 
   /**
+   * Test title_output.
+   */
+  function testPassthrough() {
+    $this->drupalGet('node');
+    $this->assertRaw('<strong>strong</strong>', 'title_output PASS_THROUGH works');
+    $this->assertNoRaw('<em>weak</em>', 'Omitting title_output leads to check_plain.');
+  }
+
+  /**
    * Test the theme callback when it is set to use an administrative theme.
    */
   function testThemeCallbackAdministrative() {

=== modified file 'modules/simpletest/tests/menu_test.module'
--- modules/simpletest/tests/menu_test.module	2010-07-07 08:05:01 +0000
+++ modules/simpletest/tests/menu_test.module	2010-08-15 07:04:07 +0000
@@ -24,6 +24,18 @@ function menu_test_menu() {
     'page callback' => 'menu_test_callback',
     'access arguments' => array('access content'),
   );
+  // Check passthrough
+  $items['menu_passthrough/1'] = array(
+    'title' => '<strong>strong</strong>',
+    'title output' => PASS_THROUGH,
+    'page callback' => 'menu_test_callback',
+    'access callback' => TRUE,
+  );
+  $items['menu_passthrough/2'] = array(
+    'title' => '<em>weak</em>',
+    'page callback' => 'menu_test_callback',
+    'access callback' => TRUE,
+  );
 
   // Hidden link for menu_link_maintain tests
   $items['menu_test_maintain/%'] = array(

=== modified file 'modules/system/system.api.php'
--- modules/system/system.api.php	2010-08-08 19:45:37 +0000
+++ modules/system/system.api.php	2010-08-15 06:50:39 +0000
@@ -872,6 +872,8 @@ function hook_page_build(&$page) {
  *     If you require only the raw string to be output, set this to FALSE.
  *   - "title arguments": Arguments to send to t() or your custom callback,
  *     with path component substitution as described above.
+ *   - "title output": CHECK_PLAIN to run the title through check_plain or
+ *     PASS_THROUGH to output as is. Defaults to CHECK_PLAIN.
  *   - "description": The untranslated description of the menu item.
  *   - "page callback": The function to call to display a web page when the user
  *     visits the path. If omitted, the parent menu item's callback will be used
@@ -3961,7 +3963,7 @@ function hook_filetransfer_backends() {
 /**
  * Control site status before menu dispatching.
  *
- * The hook is called after checking whether the site is offline but before 
+ * The hook is called after checking whether the site is offline but before
  * the current router item is retrieved and executed by
  * menu_execute_active_handler(). If the site is in offline mode,
  * $menu_site_status is set to MENU_SITE_OFFLINE.

=== modified file 'modules/system/system.install'
--- modules/system/system.install	2010-07-31 12:29:31 +0000
+++ modules/system/system.install	2010-08-15 06:53:53 +0000
@@ -1009,6 +1009,12 @@ function system_schema() {
         'not null' => TRUE,
         'default' => '',
       ),
+      'title_output' => array(
+        'description' => "Whether the title should be check_plain'd (CHECK_PLAIN) or displayed as-is (PASS_THROUGH).",
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
       'theme_callback' => array(
         'description' => 'A function which returns the name of the theme that will be used to render this page. If left empty, the default theme will be used.',
         'type' => 'varchar',
@@ -2786,6 +2792,19 @@ function system_update_7059(&$sandbox) {
 }
 
 /**
+ * Add the title_output field to the menu_router table.
+ */
+function system_update_7060() {
+  $spec = array(
+    'description' => "Whether the title should be check_plain'd (CHECK_PLAIN) or displayed as-is (PASS_THROUGH).",
+    'type' => 'int',
+    'not null' => TRUE,
+    'default' => 0,
+  );
+  db_add_field('menu_router', 'title_output', $spec);
+}
+
+/**
  * @} End of "defgroup updates-6.x-to-7.x"
  * The next series of updates should start at 8000.
  */

=== modified file 'modules/system/system.module'
--- modules/system/system.module	2010-08-09 16:54:50 +0000
+++ modules/system/system.module	2010-08-15 06:54:38 +0000
@@ -2011,7 +2011,7 @@ function system_admin_menu_block($item) 
   $default_task = NULL;
   $has_subitems = FALSE;
   $result = db_query("
-    SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.delivery_callback, m.title, m.title_callback, m.title_arguments, m.theme_callback, m.theme_arguments, m.type, m.description, m.path, m.weight as router_weight, ml.*
+    SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.delivery_callback, m.title, m.title_callback, m.title_arguments, m.title_output, m.theme_callback, m.theme_arguments, m.type, m.description, m.path, m.weight as router_weight, ml.*
     FROM {menu_router} m
     LEFT JOIN {menu_links} ml ON m.path = ml.router_path
     WHERE (ml.plid = :plid AND ml.menu_name = :name AND hidden = 0) OR (m.tab_parent = :path AND m.type IN (:local_task, :default_task))", array(':plid' => $item['mlid'], ':name' => $item['menu_name'], ':path' => $item['path'], ':local_task' => MENU_LOCAL_TASK, ':default_task' => MENU_DEFAULT_LOCAL_TASK), array('fetch' => PDO::FETCH_ASSOC));
@@ -2760,7 +2760,7 @@ function system_get_module_admin_tasks($
 
   if (empty($items)) {
     $result = db_query("
-       SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.delivery_callback, m.title, m.title_callback, m.title_arguments, m.theme_callback, m.theme_arguments, m.type, ml.*
+       SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.delivery_callback, m.title, m.title_callback, m.title_arguments, m.title_output, m.theme_callback, m.theme_arguments, m.type, ml.*
        FROM {menu_links} ml INNER JOIN {menu_router} m ON ml.router_path = m.path WHERE ml.link_path LIKE 'admin/%' AND hidden >= 0 AND module = 'system' AND m.number_parts > 2", array(), array('fetch' => PDO::FETCH_ASSOC));
     foreach ($result as $item) {
       _menu_link_translate($item);

