I feel that the creation of menus and menu items should still be in Version 2.

I'm working in a situation now that is a prime example of why this is important.
We have a platform that shares many features. But as new sites are rolled out on this platform, each site has it's own completely unique primary and footer menus. There are multiple team members working on the same site, which uses a base profile to install features and sets variables. We are extending this base profile with a subprofile which covers all these site specific needs (dummy nodes, blocks, menus, menu-items). The items in this subprofile are not going to be shared on other sites and only needs to be executed once, during the install.

By using dummy nodes we were able to build internal menu items in Primary menu. But since Drupal doesn't ship with a Footer Menu by default profiler is unable to create this for us. External linked menu-items do not get created for either menu.

It's much easier to define menus and menu-items in profiler than it is to build them into a feature. Also, profiler can be created prior to ever building a site. If there's a way to programmatically build the .info file for profiler (example: by scraping the live site) then this saves a lot of time, instead of creating the menu in Drupal UI then exporting to a feature. This also cuts down the chances of human error.

Comments

q0rban’s picture

Hmm, I'm definitely torn about this. I'm going to keep this issue open, but in the mean time, you should be able to add these functions (along with adding a install_profile_api dependency) to your base profile and get this working:

function profiler_install_menus($menus) {
  install_include(array('menu'));
  foreach($menus as $menu) {
    if ($menu) {
      install_menu_create_menu($menu['title'], $menu['name'], $menu['description']);
    }
  }
}

function profiler_install_menu_items($menu_items) {
  menu_rebuild();
  install_include(array('menu'));

  $installed = array();
  foreach($menu_items as $item) {
    // We need a link_path to do anything.
    if ($item['link_path']) {
      // We want to make sure this one hasn't already been installed.
      if (!in_array($item['link_path'], $installed) && $items = install_menu_get_items($item['link_path'])) {
        foreach($items as $menu_item) {
          if ($menu_item['mlid']) {
            $item['mlid'] = $menu_item['mlid'];
            menu_link_save($item);
          }
        }
      }
      elseif($item['link_title']) {
        install_menu_create_menu_item(
          $item['link_path'],
          $item['link_title'],
          $item['description'],
          $item['menu_name'],
          $item['plid'],
          $item['weight'],
          $item['module'],
          $item['hidden'],
          $item['has_children'],
          $item['expanded'],
          $item['customized'],
          $item['updated']
        );
      }
      $installed[] = $item['link_path'];
    }
  }
  menu_rebuild();
}
lefnire’s picture

+1 for menu_links available to profiler info files. Might add menu-item defaults a la https://gist.github.com/1355255#L49 so info doesn't have to declare all menu-item keys?

jessehs’s picture

I also was looking to do this. The main problem I was having was that the main menu is created as flat, rather than hierarchical, due to us not knowing what to specify as the parent menu link id (pid) for the link.

The following code in the my_profile.profile file will create a whole slew of pages, each of them having menu links. The cool thing is that the whole main menu hierarchy is set up during the site install. I don't know if this will work during the actual hook_install, but I'm running it after the site is installed, using an additional submit handler on the site configuration page:

<?php
function my_profile_form_install_configure_form_alter(&$form, $form_state) {
  // Run the additional install function as an additional submit handler
  $form['#submit'][] = 'my_profile_install_extra';
}
function my_profile_install_extra() {
  // Create menu links for all the pages we installed.
  $nodes = array(
    array(
      'title' => 'Understanding ...',
      'children' => array(
        array(
          'title' => 'Cause of ...',
          'children' => array(),
        ),
        array(
          'title' => 'The Human ...',
          'children' => array(),
        ),
        array(
          'title' => 'Symptoms',
          'children' => array(),
        ),
        array(
          'title' => 'Diagnosis',
          'children' => array(
            array(
              'title' => 'Diagnosis Detail Page',
              'children' => array(),
            ),
          ),
        ),
        array(
          'title' => 'Treatment',
          'children' => array(
            array(
              'title' => 'Treatment Detail page',
              'children' => array(),
            ),
          ),
        ),
        array(
          'title' => 'Types of ...',
          'children' => array(
            array(
              'title' => 'Disorders detail page',
              'children' => array(),
            ),
          ),
        ),
      ),
    ),
    array(
      'title' => 'Living with ...',
      'children' => array(
        array(
          'title' => 'Everyday Challenges',
          'children' => array(
            array(
              'title' => 'Workplace',
              'children' => array(),
            ),
            array(
              'title' => 'Social',
              'children' => array(),
            ),
            array(
              'title' => 'Family',
              'children' => array(),
            ),
          ),
        ),
        array(
          'title' => 'Tips and Tools',
          'children' => array(
            array(
              'title' => 'Educational Resources',
              'children' => array(),
            ),
            array(
              'title' => 'Tips for describing how it feels',
              'children' => array(),
            ),
            array(
              'title' => 'For your doctor visit',
              'children' => array(),
            ),
            array(
              'title' => 'Financial and Legal Advice',
              'children' => array(),
            ),
          ),
        ),
        array(
          'title' => 'Helping Others',
          'children' => array(
            array(
              'title' => 'Spouse or Partner',
              'children' => array(),
            ),
            array(
              'title' => 'Friends and Relatives',
              'children' => array(),
            ),
            array(
              'title' => 'Coworkers',
              'children' => array(),
            ),
          ),
        ),
      ),
    ),
    array(
      'title' => 'Resources for Professionals',
      'children' => array(
        array(
          'title' => 'PR and Marketing Toolkit',
          'children' => array(),
        ),
        array(
          'title' => 'Patient Toolkit',
          'children' => array(),
        ),
        array(
          'title' => 'Build Your Practice',
          'children' => array(),
        ),
      ),
    ),
    array(
      'title' => 'Get Involved',
      'children' => array(
        array(
          'title' => 'Participate in Research',
          'children' => array(),
        ),
        array(
          'title' => 'Join ...',
          'children' => array(),
        ),
      ),
    ),
  );
  $weight = 0;
  $parent_mlid = 0;
  drupal_set_time_limit(0);
  foreach ($nodes as $item) {
    $results = custom_recursive_node_save($item, $weight, $parent_mlid);
    $weight ++;
  }
}

/**
 * Helper function that will save a node, check to see if it has children, then
 * recurse if it does. It saves a menu item for each node, which is why they're
 * organized hierarchically, to preserve this in the menu structure.
 *
 * @param $item:
 *   array containing the keys 'title', 'link_title' (optional) and 'children.'
 *   Children is a recursive array, so it has the same keys.
 */
function custom_recursive_node_save($item, $weight = 0, $parent_mlid = 0) {
  $placeholder = "Portland wayfarers put a bird on it before they sold out incididunt culpa bicycle rights qui pariatur. Excepteur four loko VHS veniam dreamcatcher echo park scenester art party, cupidatat beard thundercats quinoa. Veniam jean shorts four loko aliqua, excepteur eiusmod nesciunt quis accusamus. Art party duis banksy, marfa stumptown deserunt occaecat etsy farm-to-table tumblr. Mcsweeney's squid twee, scenester fixie irony cardigan stumptown. Four loko bicycle rights marfa, sapiente biodiesel accusamus sustainable butcher velit echo park master cleanse brooklyn chambray etsy. Vero terry richardson exercitation, qui magna officia irony.";

  $node = (object) array(
    'title' => $item['title'],
    'type' => "page",
    'body' => $placeholder,
    'uid' => 1,
    'menu' => array(
      'link_title' => isset($item['link_title']) ? $item['link_title'] : $item['title'],
      'menu_name' => 'main-menu',
      'plid' => $parent_mlid,
      'weight' => $weight,
      'enabled' => TRUE,
      'description' => '',
    ),
  );
  node_save($node);
  if (!empty($item['children'])) {
    $parent_mlid = $node->menu['mlid'];
    foreach ($item['children'] as $child) {
      custom_recursive_node_save($child, $weight,  $parent_mlid);
      $weight ++;
    }
  }
  return array('nid' => $node->nid, 'weight' => $weight, 'mlid' => $node->menu['mlid']);
}
?>
q0rban’s picture

Status: Active » Postponed (maintainer needs more info)

I'm still leaning towards Features handling this sort of thing. Please give me a strong argument if you think otherwise. :)

lefnire’s picture

One reason against features is that people may want to use the profile to simply setup some dummy content, including menu-links -- but the client will likely change this dummy content off the get-go, and we don't want that to cause feature-overrides. Aka, the initial content isn't as set-in-stone as some perma-content that a feature-based module might manage.

q0rban’s picture

Version: 6.x-2.x-dev » 7.x-2.x-dev
Status: Postponed (maintainer needs more info) » Active

I'm now in favor of bringing this back. I've never used the menu_links component in Features before, but it's being used on the current project I'm on, and it's nothing but headaches all around. This should be worked on for 7.x first.

jessehs’s picture

Status: Active » Closed (duplicate)
jessehs’s picture

Status: Closed (duplicate) » Needs work

On second thought, menu links pointing to external paths or non-node paths (like taxonomy term pages) cannot be created in the way linked above. Reopening issue.

Menus, however, can be created using Features.
I believe this patch may be necessary:
#995156: Use vocabulary machine name for permissions (#31)