I'm trying to find a sneaky and self-updating way to duplicate the main menu links and place them in a footer menu. The only difference would be that the menu items would have to be glued with a delimiter, perhaps a pipe character.

I tried theme_links, theme('links', $primary_links) but none of these worked. Of course I could paste them static, but I like scalable, self-updating solutions, that's why I'm asking. So, is there a drupal function that would get menu links and implode them easily?

4 Answers 4


You can override theme('links__system_main_menu', $array) at the theme level to add "pipes" to the list markup as necessary. I just copied the source of links_system_main_menu and adjusted as necessary:

In page-front.php for example (note I added the #separator value so you could make it anything you want really. The rest of this theme() call is just plain old Zen theme code.

    <?php print theme('links__system_main_menu', array(
      'links' => $main_menu,
      'attributes' => array(
        'id' => 'main-menu',
        'class' => array('links', 'inline', 'clearfix'),
      'heading' => array(
        'text' => t('Main menu'),
        'level' => 'h2',
        'class' => array('element-invisible'),
      '#separator' => '<span class="gold_tassle">|<span>',
    )); ?>

Then in my template.php file ...

function MYTHEME_links__system_main_menu($variables) {
  $links = $variables['links'];
  $attributes = $variables['attributes'];
  $heading = $variables['heading'];
  global $language_url;
  $output = '';

  if (count($links) > 0) {
    $output = '';

    // Treat the heading first if it is present to prepend it to the
    // list of links.
    if (!empty($heading)) {
      if (is_string($heading)) {
        // Prepare the array that will be used when the passed heading
        // is a string.
        $heading = array(
          'text' => $heading,
          // Set the default level of the heading.
          'level' => 'h2',
      $output .= '<' . $heading['level'];
      if (!empty($heading['class'])) {
        $output .= drupal_attributes(array('class' => $heading['class']));
      $output .= '>' . check_plain($heading['text']) . '</' . $heading['level'] . '>';

    $output .= '<ul' . drupal_attributes($attributes) . '>';

    $num_links = count($links);
    $i = 1;

    foreach ($links as $key => $link) {
      $class = array($key);

      // Add first, last and active classes to the list of links to help out themers.
      if ($i == 1) {
        $class[] = 'first';
      if ($i == $num_links) {
        $class[] = 'last';
      if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))
           && (empty($link['language']) || $link['language']->language == $language_url->language)) {
        $class[] = 'active';
      $output .= '<li' . drupal_attributes(array('class' => $class)) . '>';

      if (isset($link['href'])) {
        // Pass in $link as $options, they share the same keys.
        $link += array('html' => TRUE);
        $title = ($i != $num_links) ? $link['title'].$variables['#separator'] : $link['title'];
        $output .= l($title, $link['href'], $link);
      elseif (!empty($link['title'])) {
        // Some links are actually not links, but we wrap these in <span> for adding title and class attributes.
        if (empty($link['html'])) {
          $link['title'] = check_plain($link['title']);
        $span_attributes = '';
        if (isset($link['attributes'])) {
          $span_attributes = drupal_attributes($link['attributes']);
        $output .= '<span' . $span_attributes . '>' . $link['title'] . '</span>';

      $output .= "</li>\n";

    $output .= '</ul>';

  return $output;
  • I was peeking into theme.inc to see how I'd wrap it into my own module, when your answer came. I just modified your code a bit not to glue the separator to the title attribute. Otherwise - wonderful, thanks! Jul 3, 2012 at 17:42
  • Actually, the code above has been isolated to cause problems, resulting in errors: headers already sent + EntityMalformedError. They have been occurring in couples, usually after the site's longer idle time. I'm retaining my acceptance for this answer though, as it points me in the right direction, albeit with the usage of menu_navigation_links() method. Jul 25, 2012 at 9:02

Rather than pollute your page markup with extraneous pipe characters, why not just take a carbon copy of the header menu, and insert the pipes with jQuery? As it's a footer menu it'll be at the bottom of the page anyway, and 99% of the time users won't scroll down quickly enough to see the insertion happening.

I use this code in any site where I need to do the same:

(function($) {
    $(function() {
      var count = $('#header-menu li').length;
      $('#header-menu li').each(function(i, v) {
        if (i < (count-1)) {
          $(v).after($('<li class="menu-separator" />').html('|'));

The above obviously applies to an element called #header-menu but you can change that for your own purposes. It works by inserting an extra <li> between each of the menu links and adding a specific class to it for easy styling.


Not sure if you want to use code but have you had a look at this module? http://drupal.org/project/menu_block/.

"It provides configurable blocks of menu trees starting with any level of any menu. And more!"


The following should work fine...

print theme('links', array('links' => $primary_links));

Use an image for the pipe.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.