In Drupal Core 7.54, we are noticing an issue with the menu system when we are using a single menu (name: "custom menu" for example purposes) with multiple languages. Below is the setup and configuration we have for the menu we are using.

The problem is that we are using 27 languages and all the menu links for the respective nodes in a particular language are all added to one "custom menu" (we do not do 1 menu per language). When the page is rendered, the menu system calls menu_tree_page_data which will make a huge query. The problem is that as the menu grows, the page load is impacted because that query is never cached and not pulled from cache. Ultimately, the menu module calls menu_navigation_links which is called from the menu.inc file. In menu.inc, on line 1852 it has $tree = menu_tree_page_data($menu_name, $level + 1).

The menu_tree_page_data is defined in the menu.inc file on line 1224. This is constantly hitting the backend and is causing significant performance issues. The query made on line 1228

do {
              $result = db_select('menu_links', NULL, array('fetch' => PDO::FETCH_ASSOC))
                ->fields('menu_links', array('mlid'))
                ->condition('menu_name', $menu_name)
                ->condition('expanded', 1)
                ->condition('has_children', 1)
                ->condition('plid', $parents, 'IN')
                ->condition('mlid', $parents, 'NOT IN')
              $num_rows = FALSE;
              foreach ($result as $item) {
                $parents[$item['mlid']] = $item['mlid'];
                $num_rows = TRUE;
            } while ($num_rows);

Is there a way to pull the menu from cache if it has been cached, if not perform the query and just create the cache? For sites using one "custom menu" for all their languages, this is a huge drag and the requirements do not allow for 1 menu per languages. Even if we cannot do anything about it since it's Drupal core's menu system, it would be helpful if it was at least language aware. The db_select above should at minimum be language aware.

Menu setup:

  1. Multilingual options: translate and localize

Menu block setup (using core menu block system to generate block of menu):

  1. visibility settings:
    1. pages: all pages except those listed (which is null so it should show in all)
    2. languages: make this block translatable (we show blocks for all languages)
    3. content types: none selected (as such there is not content type specific and it will show up in all content tyeps)
    4. roles settings: none selected (we want to show for all roles)
    5. users settings: not customizable
  2. cache settings: cache for all (global)


drupi17 created an issue. See original summary.

drupi17’s picture

Issue summary: View changes
drupi17’s picture


As mentioned, In menu.inc, on line 1852 it has $tree = menu_tree_page_data($menu_name, $level + 1). We will be changing this so that it will conditionally call menu_tree_page_data() function. The way in which we are envisioning this is to do the following (not complete as this is just the idea).

Since our menu does not change often, we were going to do up to 3 weeks for cache expiration

$cache_id = 'someid' + ($level+1)
$cache = cache_set(...)
if(cache is set) {
    //pass in appropriate parameters
    $tree = cache_get()
else  {
   //call function with the appropriate parameters. 
   $tree = menu_tree_page_data()