5

can I automatically add a menu item when I add a node to the page in Drupal?

In other words, can I associate a menu parent with a node content-type, and then automatically add the children if new nodes are added ?

thanks

aneuryzm
  • 63,052
  • 100
  • 273
  • 488

9 Answers9

4

You can do it with Rules on Drupal 7. This module: http://drupal.org/project/menu_rules adds some actions to rules. One of them is to create a menu item for a node. You select: Event: Create a node | Update a node Condition: Content type is "your content type" Action: Update a menu item for node (there is a checkbox to create the menu item if it doesnt exist)

Sinan Erdem
  • 1,014
  • 1
  • 13
  • 22
2

There's also the Menu Position module that allows to put content under specific menu entries, depending on their content type, their language and taxonomy. It also has a small API to add other criteria.

DjebbZ
  • 1,594
  • 1
  • 18
  • 34
1

Yes.

I am sure there is a module do to something like that, but you could also create your own.

There are two ways you could go about it.

You could use hook_menu() to query for the items you want and return the correct menu structure. You would need to also make sure the menu cache is rebuilt on a node save using hook_nodeapi(). See henricks' comments below about why this is a bad idea

Alternitivly you could use hook_nodeapi() to add custom menu items with menu_link_save().

Edit

hook_menu should return an array of menu items, often these are pretty static however there is nothing wrong with these arrays being dynamically generated.

So you can query the node table to get a list of nodes you want, loop through these items and dynamically create an array which contains the correct menu items.

very roughly:

function example_menu() {
  $result = db_query('select * from node where ...'); // put in your own select items and where clause
  $menu = array();
  while ($row = db_fetch_object($result)) {
    $menu['my_path/' . $row->nid;] = array(
      // See hook menu docs for what to put here.
    );
  }
  return $menu;
}
Community
  • 1
  • 1
Jeremy French
  • 11,707
  • 6
  • 46
  • 71
  • hey thanks, I'm considering the first approach. If I understood well, it is more powerful and can automatically add nodes that have been already created and saved before. Could you elaborate more "You could use hook_menu() to query for the items you want and return the correct menu structure." It is not clear how to get the nodes list from hook_menu – aneuryzm Jul 02 '10 at 08:10
  • 7
    **One should not use `hook_menu()` for this!** Creating visible menu entries is only a side effect/convenience feature of the hook, **not it's main purpose**. The 'menu' created/manipulated by this hook is the Drupal internal menu system (router table), not the visible UI menus. The visible menu entries should be created via menu_link_save, as per Jeremys second suggestion (this is what hook_menu uses itself to create the 'convenience' entries). – Henrik Opel Jul 02 '10 at 08:56
  • I explained the difference of router items vs. menu entries [in another answer](http://stackoverflow.com/questions/1844109/drupal-module-nested-menu-items/1869469#1869469). See also [When and how to use menu_links](http://drupal.org/node/217393). – Henrik Opel Jul 02 '10 at 09:02
  • I'd give a +1 for your second suggestion, and a big -1 for the first, so this cancels out. While there is indeed nothing wrong with dynamically creating multiple entries via `hook_menu` in principle, clogging up the router table with one entry per node is a huge no no, IMHO. (It will impact performance, but more importantly, it will mess up a lot of other functionality, as it would result in nodes having more than one internal path. Many modifications rely on identifiying a node page by its internal path being 'node/[nid]', and this would break with this approach!) – Henrik Opel Jul 02 '10 at 09:20
0

Here is case where you can do this.... A node campaign creating menu item 'CAMPAIGN 001' when it is created. Using default_menu_link Now another content type, 'Sub Campaign' creating a node, using campaign as EntityRef so its menu item should be under the Menu Item of campaign created earlier.

function mymodule_node_insert($node) {
  if ($node->type == 'sub-campaign') {
    if (isset($node->field_reference_campaign['und'][0]['target_id'])) {
      $campaign_node_id = $node->field_photo_album_campaign['und'][0]['target_id'];
      $campaign_loaded = node_load($campaign_node_id);
      // Get menu link id for the campaign node.
      $campaign_node_id_mlid = custom_node_mlid($campaign_node_id);
      $campaign_loaded_title = strtolower(str_replace(' ', "-", $campaign_loaded->title));
      $campaign_loaded_title_link_path = 'campaign/' . $campaign_loaded_title . '/photo-albums';
      //I will query if it exist or not, if not then will create a sub menu item.
      $link_exist = db_query("SELECT * FROM {menu_links} WHERE link_path = :link_path", array(':link_path' => $campaign_loaded_title_link_path))->fetchField();
      dsm($link_exist);
      if (!$link_exist) {
        // Create menu item under campaign.
        custom_create_menu_item($campaign_loaded_title_link_path, 'photo-albums', $campaign_node_id_mlid);
        //watchdog('glue_site - Menu Item', 'Link Created');
      }
      else {
        //dsm('Link Exist.');
        watchdog('glue_site - Menu Item', 'Link Already Exist');
      }
    }
  }
  if ($node->type == 'campaign') {

  }
}

Then a custom function to create menu item

function custom_create_menu_item($campaign_loaded_title_link_path, $type, $plid) {
  switch ($type) {
    case 'photo-albums':
      $item = array(
        'link_path' => $campaign_loaded_title_link_path,
        // If changing the title here, change it in template.php as well.
        'link_title' => 'Sub Campaign',
        'menu_name' => 'menu-campaign-menu', // Menu machine name, for example: main-menu
        'weight' => 0,
        'plid' => $plid, // Parent menu item, 0 if menu item is on top level
        'module' => 'menu',
        'router_path' => 'campaign/%/sub-campaign',
        'customized' => '1',
      );
      menu_link_save($item);
      menu_cache_clear_all();
      watchdog('glue_site - Menu Item', 'Link Created');
      break;
  }
} 

To get the mlid of parent node. Campaign node...

function custom_node_mlid($nid) {
  // Require menu node module.
  $arr = menu_node_get_links($nid);
  $mlid = array_keys($arr);
  return $mlid[0];
}

For this you need menu_node

Tanvir Ahmad
  • 273
  • 1
  • 4
  • 9
0

This is a simple problem that unfortunately the Drupal community has decided it wants to make complicated. Forget about all the hacky solutions with rules and hooks. There are two modules, depending on whether you're on Drupal 6 or Drupal 7, that solve the problem very elegantly. I advise against actually creating menu entries. Instead the two modules below dynamically render the nodes in the menu, so that your menu editor doesn't get filled with thousands of nodes. Then, for example, if you decide you want all the blog posts to be moved from [Our Blog] to [About Us]->[News] it's just a mater of changing one setting. No updating thousands of nodes.

D6 Menu Trails

D7 Menu Position

Tristan
  • 1,730
  • 3
  • 20
  • 25
0

You should take a look at the Auto Menu module - while the Drupal 6 version is still a dev release, it might cover your needs. If not, you can take it as an example of how to use menu_link_save() to create your own solution.

Henrik Opel
  • 19,341
  • 1
  • 48
  • 64
0

I would also go for a menu_link_save() call. Together with the Rules module, you can set up an action whenever a new node is saved, to create an appropriate menu item automatically.

You might want to have a look at the tutorial I wrote some time ago, which deals with programatically creating menu items using menu_link_save() and Rules: http://jan.tomka.name/blog/programmatically-creating-menu-items-drupal

Jan Tomka
  • 11
  • 1
0

It looks like there's a Drupal module that does this: Auto Menu. Some more details about this module (from its project page):

The Auto Menu module automatically generates menu entries on node creation/edition. Parent menu item can be specified on a per content type basis.

This module acts when the menu section of a node is left empty only. So, users can still organize menus manually. Moreover, default setting for content types is to not create menu items automatically.

Community
  • 1
  • 1
-1

Menu Views is an interesting module for Drupal 7 to automatically generate menu links. It allows you to use the power of Views to create menu links and can be used out-of-the-box in combination with modules such as Superfish and Nice Menus.

(PS: my reputation is not high enough to provide more than two links, therefore I have marked the other modules bold instead of providing hyperlinks)

Watergate
  • 111
  • 2
  • 3