How to add a new tab (e.g. like "Dashboard" or "Reports")

I was watching the development videos (Video: Developing farmOS) and it was mentioned briefly at the end of the first one that it is possible to have a page appear as a tab (i.e. alongside “Dashboard”, “Quick forms” and “Reports”). Is there a short example to work from or some documentation that would help me get started with adding such a tab for a custom module? Any pointers or nudges in the right direction would be appreciated. Thanks.

I think I figured this out… If it is of interest to anyone later the key insights were:

  • Use the farm/reports and farm/quick modules as a guide.
  • In hook_menu use: $items['farm/tabs'] = ... where tabs is the name that appears in the URL.
  • Changes to the hook_menu method appear to require a module off/on cycle to take effect.
  • Changes to the page callback method are live and do not require a module off/on cycle.

Here is a minimum implementation of a new tab with 2 sub-tabs that can appear in the www/sites/all/modules/ directory.

<?php
/**
 * @file
 * Tab Test module.
 */

 function tab_test_permission() {
   return array(
     'view tab test' => array(
       'title' => t('View tab_test'),
     ),
     'configure tab test' => array(
       'title' => t('Configure tab_test'),
     ),
   );
 }

 function tab_test_farm_access_perms($role) {
   $perms = array();

   // Load the list of farm roles.
   $roles = farm_access_roles();

   // If this role has 'edit' access, allow them to see these tabs.
   if (!empty($roles[$role]['access']['edit'])) {
     $perms[] = 'view tab test';
   }

   // If this role has 'config' access, allow them to also configure tab test.
   if (!empty($roles[$role]['access']['config'])) {
     $perms[] = 'configure tab test';
   }

   return $perms;
 }

 /**
 * Implements hook_menu().
 */
function tab_test_menu() {
  $items = array();

  $items['farm/tabs'] = array(
    'title' => 'Tabs',
    'page callback' => 'tab_test_view',
    'access arguments' => array('view tab test'),
    'type' => MENU_LOCAL_TASK,
  );
  $items['farm/tabs/info'] = array(
    'title' => 'Info',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -100,
  );
  $items['farm/tabs/info2'] = array(
    'title' => 'Info2',
    'type' => MENU_LOCAL_TASK,
    'page callback' => 'tab_test_view2',
    'access arguments' => array('view tab test'),
    'weight' => 100,
  );

  return $items;
};

// Changes to the callback functions below are live.  
// The function for the callback set above requires a module off/on cycle.

function tab_test_view() {
  return t('Select a tab from the menu above.');
};

function tab_test_view2() {
  return t('Some different other stuff.');
};
1 Like

Hi @braught - welcome to the farmOS forum!

Sounds like you figured it out. Well done! :slight_smile:

For future reference, the documentation for Drupal 7’s hook_menu() is available here: https://api.drupal.org/api/drupal/modules!system!system.api.php/function/hook_menu/7.x

Changes to the hook_menu method appear to require a module off/on cycle to take effect.

The menu router item information is only read when Drupal has reason to believe changes have been made to it, and are then stored in the {menu_router} table for faster lookups. Enabling modules triggers this, as you noticed. You can also simply submit the modules form (/admin/module) without turning any off/on to achieve the same affect. Alternatively, if you have Drush installed, you can run drush cc menu.

Note: this all changes in Drupal 9 / farmOS 2.x (in active development), but the concepts are mostly the same. This might help when it comes time to upgrade: https://www.lullabot.com/articles/what-happened-to-hook_menu-in-drupal-8

Hope that helps! Thanks for sharing your lessons with the community!

1 Like