May 23, 2014

Implementing multiple tabs on a page

In D7 to provide multiple tabs you can implement hook_menu() and within it, define items with types of MENU_LOCAL_TASK and MENU_DEFAULT_LOCAL_TASK.

To do multiple page tabs in Drupal 8 use its routing system and a separate .yml file instead. In this example, three tabs are created for the Optimizely admin UI.

First, routes need to be defined in the .routing.yml file, one for each tab.

  modules/custom/optimizely/optimizely.routing.yml

File contents:
optimizely.listing:
  path: /admin/config/system/optimizely
  defaults:
    _content: \Drupal\optimizely\Controller\OptimizelyController::helloListing
    _title: Optimizely
  requirements:
    _permission: administer optimizely

optimizely.add_update:
  path: /admin/config/system/optimizely/add_update
  defaults:
    _content: \Drupal\optimizely\Controller\OptimizelyController::helloAddProject
    _title: Optimizely
  requirements:
    _permission: administer optimizely

optimizely.acct_info:
  path: /admin/config/system/optimizely/settings
  defaults:
    _content: \Drupal\optimizely\Controller\OptimizelyController::helloAcctInfo
    _title: Optimizely
  requirements:
    _permission: administer optimizely

Second, there is a .local_tasks.yml file in which the tabs themselves are defined.

  modules/custom/optimizely/optimizely.local_tasks.yml

File contents:
optimizely.listing_tab:
  route_name: optimizely.listing
  title: 'PROJECT LISTING'
  base_route: optimizely.listing
  # route_name == base_route, this tab displays leftmost.

optimizely.add_project_tab:
  route_name: optimizely.add_update
  title: 'ADD PROJECT'
  base_route: optimizely.listing
  weight: 1

optimizely.acct_info_tab:
  route_name: optimizely.acct_info
  title: 'ACCOUNT INFO'
  base_route: optimizely.listing
  weight: 2
Notes.
  • Indentation matters! This is not only for readability but is part of the YAML syntax. Elements that are at the same level must have exactly the same indentation. Tab characters may not be used for indenting.
  • The _title property in the routing file serves as a page title whereas the title property in the local_tasks file serves as a tab label.
  • The base_route property is used to create groupings of tabs. Tabs that have the same value for base_route  belong to the same group.
  • For a particular tab, if  its route_name is the same as the base_route, that tab is the default and is displayed leftmost.
  • For other tabs, the weight property may be used to order them. If there is no weight property, they are displayed in reverse order, i.e. the last one defined in the local_tasks file will render to the left of the others. 
  • YAML has a special syntax that provides block literals so that string values of properties may be split over multiple lines. I tried unsuccessfully to use this in order to make the long paths for the _content properties more readable in this post. Unfortunately, that resulted in unwanted space characters embedded in the paths. That broke the routing process.

Update for Drupal 8, beta 1: The .local_tasks.yml files have been renamed to .links.task.yml. The source article below is up-to-date on this. You can also see http://optimizely-to-drupal-8.blogspot.com/2014/08/mv-localtasksyml-linkstaskyml.html

Update: see  http://optimizely-to-drupal-8.blogspot.com/2014/12/beta-3-beta-4-routes-use-controller.html


Source:

Providing module-defined local tasks
https://drupal.org/node/2122253

2 comments:

  1. > YAML has a special syntax that provides block literals so that string
    > values of properties may be split over multiple lines.

    http://stackoverflow.com/questions/3790454/in-yaml-how-do-i-break-a-string-over-multiple-lines

    ReplyDelete
    Replies
    1. The problem is that the lines are concatenated into one string as intended, but the line breaks that are removed leave behind a space character. Within a path, those extra spaces break the path. It could be there's a way to avoid those embedded spaces but I haven't found it yet.

      Delete