When using node_view() to display a node (via return from a function that's called in hook_menu()) the usual View/Edit tabs are missing.

Is this expected behaviour?

3 Answers 3


Yes this is expected. The reason they are there, is because the path of view a node is at node/[nid] and the edit/view is at node/[nid]/edit. If you changed the default node path with hook_menu_alter the tabs on all nodes would disappear.

The reason they are there, is because they are of type, MENU_LOCAL_TASK, check out the documentation on hook_menu, if you need to know more.


It is the expected behavior. node_view()'s purpose is to build the node view, not to create also the other tabs that you normally see at http://example.com/node/<nid>.

If you want to emulate what done in a node page, you should define the following menu structure (I have chosen page randomly):

 * Implements hook_menu().
function mymodule_menu() {
  $items['page/%node'] = array(
    'title callback' => 'node_page_title', 
    'title arguments' => array(1), 
    'page callback' => 'mymodule_page_view', 
    'page arguments' => array(1), 
    'access callback' => 'node_access', 
    'access arguments' => array('view', 1), 
    'type' => MENU_CALLBACK,
  $items['page/%node/view'] = array(
    'title' => 'View', 
    'weight' => -10,
  $items['page/%node/edit'] = array(
    'title' => 'Edit', 
    'page callback' => 'mymodule_page_edit', 
    'page arguments' => array(1), 
    'access callback' => 'node_access', 
    'access arguments' => array('update', 1), 
    'weight' => 1, 
    'file' => 'node.pages.inc',
    'file path' => drupal_get_path('module', 'node'), 
    'type' => MENU_LOCAL_TASK,

  return $items;

mymodule_page_view() is the page callback that would call node_view().


To move all potential tabs added by modules to a node, and make them visible on another new custom path alter the links dynamically when the menu cache router is re-built.

Stick the following in a module:

 * Implementation of hook_menu_alter().
function example_menu_alter(&$callbacks) { 
  foreach($callbacks as $path => $menu) {

    if (strpos($path, 'node/%node/') !== FALSE) {
      $newpath = str_replace('node/%node/', 'customurl/%/%/%/%node/', $path);
      $callbacks[$newpath] = $menu;
      unset ($callbacks[$path]);

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.