Drupal 7 Expanded Menu Control On Nodes

1st December 2011 - 5 minutes read time

I recently noticed a strange little issue with Drupal 7 that seemed like either an oversight or a decision I don't agree with. Essentially, when a node is created with a menu item in place the extended flag on the menu will not be set, but the control is also not available on the menu admin page. This means that when you are trying to print out a hierarchical menu structure you need to create the page, go into the menu admin area, access the menu, click on edit to access the menu item and change the setting there.

To get around this I set about creating a little module that would add a form control to the menu options section on the node edit form. This single checkbox is used to override any settings that the menu module creates with regards to the extended menu parameter.

The first thing to do is create a simple info file for the module. I include this here for completeness.

name = Node expanded menu
description = Allows users to set the expanded nature of the menu item on creation.
core = 7.x

I normally wouldn't create an install file for such a simple module, but in this instance we need to to prevent the loading of the module code until after the menu module has inserted its form items into the node form. The hook_install() call here just adds some weight to this modules entry in the system table to make Drupal load the module slightly later than it would have otherwise. Without this here our module would run before the menu module had created its form component and we wouldn't be able to do anything. I have tested this with a value of 1 and found that it works perfectly well, if it doesn't in your setup then you might need to increase this value slightly.

<?php

/**
 * @file
 * Node expanded menu install file.
 */

/**
 * Implements hook_install().
 */
function node_expanded_menu_install() {
  // Make sure this module loads after menu.
  db_query("UPDATE {system} SET weight = 1 WHERE name = 'node_expanded_menu'");  
}

Finally, we need to create some hooks that will create the form element and save the resulting values to the database. The first hook to create is a hook_form_[form-id]_alter() hook that will allow us to intercept and change the node edit form. A hidden form element called expanded already exists within the menu section of our form so we only need to alter it to suit our needs. All we need to do is set the type of the element to be a checkbox and swap the #value and #default_value attributes around to stop the original value being saved. If the nid of the node has been set then we set the default value of the checkbox to 1, otherwise we use the existing value of the expanded element. For completeness I have also added in the same title and description that exists within the menu admin forms.

<?php

/**
 * @file
 * node_expanded_menu module file
 */

/**
 * Implements hook_form_form-id_alter().
 */
function node_expanded_menu_form_node_form_alter(&$form, &$form_status) {
  if (isset($form['menu']['link'])) {
    // Alter the expanded form element to override the default setting
    $form['menu']['link']['expanded']['#weight'] = 25;
    $form['menu']['link']['expanded']['#type'] = 'checkbox';
    $form['menu']['link']['expanded']['#title'] = t('Show as expanded');
    $desctiption = t('If selected and this menu link has children, the menu will always appear expanded.');
    $form['menu']['link']['expanded']['#description'] = t($desctiption);    
    if (isset($form['nid']) && is_null($form['nid']['#value'])) {
      $form['menu']['link']['expanded']['#default_value'] = 1;
    } else {
      $form['menu']['link']['expanded']['#default_value'] = $form['menu']['link']['expanded']['#value'];
    }
	unset($form['menu']['link']['expanded']['#value']);
  }
}

Now, when a user creates a menu link on a node that allows it they will be able to chose if the children of that menu item are displayed.

Comments

Permalink
Thank you very much for this!

isi (Sat, 01/04/2014 - 17:35)

Add new comment

The content of this field is kept private and will not be shown publicly.