3

I need to add an element somewhere within, or directly before/after, the main menu block. For example, the generated HTML should be something like this:

<div id="main-navigation">
  <div class="block block-system" id="block-system-main-menu">
    <div class="block-inner clearfix">
      <div class="content clearfix">
        <ul class="menu">
          <li class="first expanded">
            <a href="">About</a>
            <ul class="menu">
              <li class="first leaf">
                <a href="">General Info</a>
              </li>
              <li class="leaf"><a href="">Video</a></li>
                <!-- ... other menu items -->
            </ul>
          </li>
        </ul> <!-- this ends the top level main ul.menu -->
        <!-- a div added here would be ok -->
      </div>
    </div>
  </div>
</div>
<!-- or a div added here would be ok -->

I am currently trying hook_block_view_alter() and have tried multiple variations of something like this:

function theme_block_view_alter(&$data, $block) {
  if ($block->delta == 'main-menu'
    && $block->region == 'menu') {
    $data['content'][] = array(
      '#markup' => '<div class="."><a href="#top">Close Mobile Menu</a></div>'
    );
  }
}

which is the closest I have come. This adds the div within ul.menu (top level) after the last li element; that won't work.

I can't seem to find a theming function for the menu as a whole, just theme_menu_links(). I see the theme wrapper menu_tree__main_menu within $data in hook_block_view_alter(), but I don't see a file or function that resembles that.

I'm aware that there may be a much better solution that I'm just not thinking of, so I'll state the final goal:

  1. Absolute positioned menu. (I can work with #main-navigation being absolute and the element coming after it or with ul.menu being positioned, and the element coming after it.)
  2. A link that follows the menu in markup, but is outside of the absolute positioned menu, so that I can position relative to window, not the ul.

Thanks!

2 Answers 2

2

To accomplish all your goals, you need to implement these three functions:

Create one template file for the block with your menu.

template.php

/**
 * Implements hook__preprocess_block().
 */
function YOURTHEME_preprocess_block(&$variables, $hook) {
  // allow to use block templates depend on delta
  // example: delta = main-menu ; template file: block--main-menu.tpl.php
 if ($variables['block']->delta == 'main-menu') {
    $variables['theme_hook_suggestions'][] = 'block__' . str_replace('-', '_', $variables['block']->delta);
 } 
}

/**
 * Main menu
 * Implements theme__menu_tree().
 */
function YOURTHEME_menu_tree__main_menu($variables) {
    global $level;
    $div = ($level == 1) ? '<div> ... some div next to the main ul ... </div>' : '';
    $ul = '<ul class="menu">' . $variables['tree'] . '</ul>' . $div;
    return $ul;
}

/**
 * Main menu
 * Implements theme__menu_link().
 */
function YOURTHEME_menu_link__main_menu($variables) {

  $element = $variables['element'];
  $title = $element['#title'];
  $sub_menu = '';

  // global menu level variable. 
  // within theme_menu_tree() at first level has always value = 1
  // but not here, that's why $depth will have to be defined separately
  global $level;
  $level = $element['#original_link']['depth'];

  // if you will need $depth, it must be defined separately
  // $depth = $element['#original_link']['depth']; 

  // submenu
  if ($element['#below']) {
    $sub_menu = drupal_render($element['#below']);
  }

  // link output
  $output = l($title, $element['#href'], $element['#localized_options']);

  // if link class is active, make li class as active too
  if(strpos($output,"active")>0){
    $element['#attributes']['class'][] = "active";
  }

  $attr = drupal_attributes($element['#attributes']);
  return  '<li' . $attr . '>' . $output .$sub_menu . "</li>\n";
}

block--main-menu.tpl.php

<?php
/**
 * @file
 * theme's implementation to display a block with the main menu.
 */     
?>
<div id="main-navigation">
  <div class="block block-system" id="block-system-main-menu">
    <div class="block-inner clearfix">
      <div class="content clearfix">
        <?php print $content; ?>
      </div>
    </div>
  </div>
</div>

<!-- or a div added here would be ok -->
<div> ... some div next to the main navigation div ... </div>

Results

screenshot

1

What about page.tpl.php? It will allow you the add the extra markup before / after the menu. I think that theme_preprocess_page may also do the job.

1
  • Thanks for the suggestion. I'd prefer to keep it in the block if possible though. I think my issue is I don't yet understand renderable arrays. Aug 8, 2013 at 0:32

Your Answer

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

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