0

In hook_preprocess_page in my template.php I'm using this code:

// Get the entire main menu tree
$main_menu_tree = menu_tree_all_data('main-menu');
// Add the rendered output to the $mobile_menu variable
$mobile_menu = menu_tree_output($main_menu_tree);

To generate the entire menu tree of main menu

Thinking that preprocess_page is executed on every page (please confirm this if it's true) I cached the above code in this way:

$cid = 'ctm_mobile_menu:' . $vars['language']->language;
$mobile_menu = &drupal_static(__FUNCTION__);
if (!isset($mobile_menu)) {
  if ($cache = cache_get($cid)) {
    $mobile_menu = $cache->data;
  }
  else {
    // Get the entire main menu tree
    $main_menu_tree = menu_tree_all_data('main-menu');
    // Add the rendered output to the $mobile_menu variable
    $mobile_menu = menu_tree_output($main_menu_tree);
    cache_set($cid, $mobile_menu, 'cache');
  }
}

But my doubt now is: is caching effectively necessary here? or menu_tree_all_data and menu_tree_output already does caching by itself?

My concern is that I'm caching already cached data and this can generate bad loops.. I don't know please help me

  • Is there a particular reason you are not using the existing menu blocks on your page(s)? – mpdonadio Apr 9 '14 at 16:47
  • I need a pure ul li output to reformat the whole menu with a jquery plugin, and also because this menu is printed out only on mobile devices (code above is not complete). – MXT Apr 9 '14 at 20:06
3

No need to cache menu_tree_all_data() as it is already cached; which leaves menu_tree_output(). This function looks fairly light; but it really depends on how many items are in $main_menu_tree. Note that it's not 100% safe to cache menu_tree_output() the way you're currently using it as it uses menu_get_item(). If you were to use the tab_root_href key as part of the cid then that would probably work. If this code only gets called once (my guess as it's in hook_preprocess_page()) then the static cache will not help. The important questions are how fast is your cache backend, how many items are in $main_menu_tree, and how often does this code get called. Knowing that will tell you what's better.

Questions like this can be answered with some help from microtime(). Example below:

// Get current menu item.
$router_item = menu_get_item();
$menu_name = 'main-menu';
// Get the cache ID.
$cid = 'ctm_mobile_menu:' . $vars['language']->language . ':' . $router_item['tab_root_href'] . ':' . $menu_name;

// Try core static cache.
$menu_output = &drupal_static('menu_tree', array());
if (!empty($menu_output) && !empty($menu_output[$menu_name])) {
  $mobile_menu = $menu_output[$menu_name];
}
else {
  // Try cache backend
  if ($cache = cache_get($cid) && !empty($cache->data)) {
    $mobile_menu = $cache->data;
  }
  else {
    // Get the rendered output for the $menu_name variable.
    $mobile_menu = menu_tree($menu_name);
    // Save to the cache bin.
    cache_set($cid, $mobile_menu, 'cache');
  }
}



$time_start = microtime(true);
    // Get the entire main menu tree.
    $main_menu_tree = menu_tree_all_data('main-menu');
    // Add the rendered output to the $mobile_menu variable
    $mobile_menu = menu_tree_output($main_menu_tree);
$time_end = microtime(true);
$time = round($time_end - $time_start, 4);
echo "Did non-cached in $time seconds\n";



$time_start = microtime(true);
    // Get current menu item.
    $router_item = menu_get_item();
    // Get the cache ID.
    $cid = 'ctm_mobile_menu:' . $vars['language']->language . ':' . $router_item['tab_root_href'];

    // Try cache backend
    if ($cache = cache_get($cid)) {
      $mobile_menu = $cache->data;
    }
$time_end = microtime(true);
$time = round($time_end - $time_start, 4);
echo "Did cached in $time seconds\n";
| improve this answer | |
  • $main_menu_tree counts 273 items, I'm using REDIS as cache backend (on nginx), and this code is called one time for page, but every page calls it (only if it is requested by a Mobile/tablet device). I'm not sure to understand the suggested use of $router_item['tab_root_href'] as additional key because this menu (that is the default main drupal menu) doesn't change between pages, but is identical in the whole site (I'm already using my above cache solution on live site and it works without it) (sorry if I'm a bit confused but I'm not a so skilled programmer) – MXT Apr 9 '14 at 22:57
  • menu_tree_output() uses $router_item['tab_root_href'] to see if the given menu item is active. By not using this in your cid, the menu will have the same thing be marked active all the time on all pages. What does the microtime say? is the cache backend quicker than using menu_tree_output()? – mikeytown2 Apr 9 '14 at 23:01
  • Did non-cached in 0.0359 sec, Did cached in 0.0042 seconds – MXT Apr 9 '14 at 23:51
  • caching is ~3ms faster on your setup. It's up to you if 3ms is worth caching :) – mikeytown2 Apr 9 '14 at 23:56
  • 1
    Does this take into account permissions? Don't you also need to add $user->uid to the $cid? – mpdonadio Apr 10 '14 at 1:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.