17th August 2011

Creating an extra tab for a content type, like View and Edit.

Alli Price
Developer

On a recent project, we implemented a new content type on an existing Drupal site. One of the requirements of this content type was to allow a high level of user interaction, but also give detailed reporting per-node.

To give access to reports per node we added in our own custom tab, we followed the example of node and webform to give the result we wanted. Here's how you do it.

Please note:

  • All code in this post is for Drupal 6.
  • Our example code will assume you've got a custom module created and enabled called "my_module", you should replace any instances of my_module with the name of your custom module.
  • The content type we want the tab to appear on is "report".
  • If you make any tweaks to the code relating to hook_menu, or my_module_menu_load, you will want to flush your menu router cache to ensure it takes effect.

First, we implement our own permission which users will need to see the new tab:

/** * Implementation of hook_perm(). */ function my_module_perm() { return array('access custom node reports'); }

Next we add in a custom menu item:

/** * Implementation of hook_menu(). */ function my_module_ menu() { $items = array(); // The report tab for our new content type $items['node/%my_module_menu/report'] = array( 'title' => 'Custom report', 'page callback' => 'my_module_report_tab_callback', 'page arguments' => array(1), 'access arguments' => array('access custom node reports'), 'weight' => 2, 'type' => MENU_LOCAL_TASK, ); return $items; }

Our custom menu item will be placed after the standard "View" and "Edit" tabs, however, if you want to influence where our new tab appears in the list, you can alter the weight value. The new tab will live at node/x/report (with x being a node id), and finally points to our callback function my_module_report_tab_callback. For more information on the options used, refer to the API for hook_menu.

The next part is to define the menu loader callback. In this function we determine whether or not the tab should be shown on the node page, ensuring that the tab only appears on our specific content type.

The way we reference this function is in our hook_menu menu item, note that the menu item path is node/%my_module_menu/report, because of this Drupal checks in with the function my_module_menu_load providing it exists. Our my_module_menu_load is expected to return either true or false. As we've loaded the node object we pass it back, where it is then sent on to our page callback which counts as true.

You can find this particular function which isn't a hook per se, in include/menu.inc, called _menu_router_build.

/** * Menu loader callback. */ function my_module_menu_load($nid) { if (!is_numeric($nid)) { return FALSE; } // Load the full node so that we can determine that it's the right // content type. $node = node_load($nid); // If the node has failed to load, or isn't the right content type, do not show. if (!isset($node->type) || $node->type != 'report') { return FALSE; } return $node; }

The last step is define the callback function which returns the tab content.

/** * my_module_report_tab_callback(). * * Page callback for the results tab which appears * on open & closed competition nodes. */ function my_module_report_tab_callback($node) { print t("You're viewing the report tab for node id @nid", array('@nid' => $node->nid)); }

This function simply outputs some text, although you can modify this to suit your needs.

There you have it! Your tab is now on whichever content type(s) you like.

As ever, if you've got any questions you can ask them via the comment form below.