Comments

rroblik’s picture

Issue summary: View changes

Hi,

I'm encountering issue whit submenu when I use view (with module Menu Views)
Submenu is only outputed as

<ul ... ><li><a href="<view>"></a></li></ul>

The problem seem to came from bootstrap_menu_link() (inside menu-link.func.php)
When I comment this function, my view is outputted as desired (raw, without bootstrap class of course)

My question is : how to disable this hook (bootstrap_menu_link) without modify the main theme ?
or
Is that normal view to not render (ouput) when used as (sub)menu with Bootstrap ?

Thanks for answers.

NB : Menu Views module use hook_menu_link also, so as Bootstrap is a template, I think bootstrap_menu_link hook is running after the module, but I'm not sure ...

tahiticlic’s picture

Hi,

same here!

I can't find where the conflict is, any help welcome :-)

tahiticlic’s picture

Hi,

here is a solution (customized for our purpose, but the idea is to treat $view as a sub menu in a custom hook_theme_link implementation) :

function mycustom_theme_menu_link($variables) {
  $view = _menu_views_replace_menu_item($variables['element']);

  $element = $variables['element'];
    $sub_menu = '';
    $menuName = $variables['element']["#original_link"]["menu_name"];

    if ($element['#below']) {
        if ($menuName == "main-menu") {
            unset($element['#below']['#theme_wrappers']);

            $sub_menu = "<ul class='sub-menu'>" . $view . drupal_render($element['#below']) . '</ul>';
        } else {
            $sub_menu = drupal_render($element['#below']);
        }
    }

    // si on a une vue, c'est elle qu'on met en dessous
    if ($view !== FALSE) {
        if (!empty($view)) {
            $sub_menu = $view;
        }
    }

    $output = l($element['#title'], $element['#href'], $element['#localized_options']);
    return '<li' . drupal_attributes($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";

}
plazik’s picture

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

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

@Plazik According to the amount of differences, I can't see how it is a solution... Have you explored all the possible effects of such a file regression ?

rroblik’s picture

@tahiticlic agree with you

But this tread is pretty old ... my workaround is not far away from your's.
Your fix #3 should be adapted because if the submenu is a view, the parent <a> still have "<view>" inside href attribute.

Here is pieces of my fix


function mytheme_menu_link(&$vars) {
  $element = $vars['element'];

  if (module_exists('menu_views') && $element['#href'] == '<view>') {
    return _mytheme_menu_views_menu_link($vars);
  }

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

function _mytheme_menu_views_menu_link(&$vars) {
  // Only intercept if this menu link is a view.
  $view = _menu_views_replace_menu_item($vars['element']);
  if ($view !== FALSE) {
    if (!empty($view)) {
      $sub_menu = '';

      // Optionnal : altering classes or other attributes
      $classes = array();
      $item = _menu_views_get_item($vars['element']); // Function from menu_views module
      foreach (explode(' ', $item['view']['settings']['wrapper_classes']) as $class) {
        if (!in_array($class, $classes)) {
          $classes[] = $class;
        }
      }
      $vars['element']['#attributes']['class'] = $classes;
      // EOF optionnal styling

      if ($vars['element']['#below']) {
        $sub_menu = render($vars['element']['#below']);
      }

      return '<div' . drupal_attributes($vars['element']['#attributes']) . '>' . $view . $sub_menu . "</div>\n";
    }
    return '';
  }

  return theme('menu_views_menu_link_default', $vars);
}

I'm not sure what is the best solution / fix but I hope Bootstrap theme will handle a fix to be natively compatible with menu_views module

Cheers

plazik’s picture

@rroblik your fix is only for menu_views module but my fix is for all modules (example, path_breadcrumbs module). It's not the best and not final but it works.

@tahiticlic registry.inc file contains functions specific to the theme registry but bootstrap-7.x-3.1-beta2 doesn't work well with other modules themes.

The problem is in registry.inc file and we should find the proper fix.

markhalliwell’s picture

Priority: Major » Normal
Status: Active » Postponed (maintainer needs more info)
Issue tags: -Integration with Menu Views

@Plazik, can you please elaborate on: "The problem is in registry.inc file and we should find the proper fix."? What, exactly, is the problem?

plazik’s picture

Status: Postponed (maintainer needs more info) » Active
markhalliwell’s picture

Title: Not working with menu views » Detect when modules alter theme hook templates/functions
Category: Bug report » Feature request
Status: Active » Postponed

I'm really tempted to say this is really just "works as designed" more than anything. There's actually nothing wrong with the theme registry; themes are supposed to override theme hooks provided by modules.

Obviously, what this issue really boils down to is: there's a conflict between the module (which provides advanced/different display logic) and theme (which provides its own classes/markup to work with the framework).

When a module (such as menu_views or path_breadcrumbs) implements an alter though, it has always been up to the the theme (or sub-theme) to re-implement that template (function) if needed. The "solution" for these types of conflicts are usually never very "easy" to solve and almost always have to be handled manually in some sort of fashion.

Furthermore, it's often the module that do not implement/segregate the theme hook properly and put in too much custom logic that it's nearly impossible to just "inject" the necessary bootstrap classes/markup. We end up having to copy over the entire function for this module's logic and end up having to maintain this block of the modules code (which isn't ideal for anyone involved).

After thinking about this though, there may be one possible way to semi-help with this "issue", so I'll mark as a feature request and postpone for a rainy day:

  1. It may be possible to "detect" if a theme hook as been overridden by a module by checking if the theme hook function starts with theme_ or not. There is not anything currently in the registry that would help "detect" if a module has overridden a template however, as this relies solely on the path to the template file (which cannot be reverse engineered).
  2. If the theme function does start with theme_, then we override the function normally bootstrap_HOOK().
  3. If the theme function doesn't start with theme_, we can use the entire function as the theme hook to check for a file/function (i.e. bootstrap_path_breadcrumbs_breadcrumb() or bootstrap_menu_views_menu_link()).
  4. If there is no specific bootstrap implementation for this module overridden theme hook, then we don't touch it and let the module take over. This may, however, cause the implementation to be "un-styled" as they will likely not have any of the bootstrap based classes/markup.
markhalliwell’s picture

Status: Postponed » Closed (won't fix)

This isn't going to happen.

davemybes’s picture

I recently hit this same issue and after trying (and failing) the solutions presented here and elsewhere, I came up with my own that appears to work. Apologies for posting on a closed issue, but people searching for this issue will find this first.

Using Bootstrap 7.x-3.10 and Menu Views 7.x-2.4, I created a theme override for bootstrap_menu_link in my custom theme's template.php. I copied the entire bootstrap_menu_link function and added in some code for Menu Views. The complete function is below and should be all you need to make this work. However, if you usedany extra wrapper classes or you enabled the View Title, you might need to add in some things to the code below. For me, all I wanted was the list items. I didn't use any arguments either, but I've included the code for that, just in case.

function mytheme_menu_link($variables) {
  $element = $variables['element'];
  $sub_menu = '';

  $title = $element['#title'];
  $href = $element['#href'];
  $options = !empty($element['#localized_options']) ? $element['#localized_options'] : array();
  $attributes = !empty($element['#attributes']) ? $element['#attributes'] : array();

  if ($element['#below']) {
    // <-- Start added custom code...
    // Menu Views has an issue with Bootstrap 3.1 and up, so we have to manually
    // get the Views output added here.
    if (module_exists('menu_views')) {
      foreach ($element['#below'] as $item) {
        if (!empty($item['#href']) && $item['#href'] == '<view>') {
          $view_name = $item['#localized_options']['menu_views']['view']['name'];
          $view_display = $item['#localized_options']['menu_views']['view']['display'];
          $view_args =  $item['#localized_options']['menu_views']['view']['arguments'];
          $output = views_embed_view($view_name, $view_display, $view_args);
          // Assign the View output to a new key to be used later.
          $element['#view_output'] = $output;
        }
      }
    }
    // ... end added custom code -->

    // Prevent dropdown functions from being added to management menu so it
    // does not affect the navbar module.
    if (($element['#original_link']['menu_name'] == 'management') && (module_exists('navbar'))) {
      $sub_menu = drupal_render($element['#below']);
    }
    elseif ((!empty($element['#original_link']['depth'])) && ($element['#original_link']['depth'] == 1)) {
      // Add our own wrapper.
      unset($element['#below']['#theme_wrappers']);
      $sub_menu = '<ul class="dropdown-menu">' . drupal_render($element['#below']) . '</ul>';

      // <-- Next bit of custom code...
      // We have to wait until all non-menu_views items are in the sub-menu, before
      // we can put our View output in there.
      $bad_view = '<a href="/%3Cview%3E" title=""></a>';
      if (!empty($element['#view_output']) && strpos($sub_menu, $bad_view)) {
        $sub_menu = str_replace($bad_view, $element['#view_output'], $sub_menu);
      }
      // ... end next bit of custom code -->

      // Generate as standard dropdown.
      $title .= ' <span class="caret"></span>';
      $attributes['class'][] = 'dropdown';

      $options['html'] = TRUE;

      // Set dropdown trigger element to # to prevent inadvertant page loading
      // when a submenu link is clicked.
      $options['attributes']['data-target'] = '#';
      $options['attributes']['class'][] = 'dropdown-toggle';
      $options['attributes']['data-toggle'] = 'dropdown';
    }
  }

  // Filter the title if the "html" is set, otherwise l() will automatically
  // sanitize using check_plain(), so no need to call that here.
  if (!empty($options['html'])) {
    $title = _bootstrap_filter_xss($title);
  }

  return '<li' . drupal_attributes($attributes) . '>' . l($title, $href, $options) . $sub_menu . "</li>\n";
}

amaisano’s picture

@incrn8 what is your code here attempting to check for, exactly:

$bad_view = '';
if (!empty($element['#view_output']) && strpos($sub_menu, $bad_view)) {
  $sub_menu = str_replace($bad_view, $element['#view_output'], $sub_menu);
}

I use a radix sub-theme and I've had to tweak some things to work with radix's *very* aggressive theme_menu() overrides.

When I used your code here it didn't really work, and I got "Warning: strpos(): Empty needle".

I changed it to be the following, but I'm worried that if normal, non-menu_views links are added things will get screwed up:

  $bad_view = '';
  // drupal_set_message($sub_menu, 'warning');
  if (!empty($element['#view_output'])) {
    $sub_menu = '<ul class="dropdown-menu">' .$element['#view_output']. '</ul>';
  }

I'm confused on the use of '$bad_view' I suppose.

markhalliwell’s picture

It should be noted that the "solution" to get Menu Views and a theme that alters the registry too (like this one) is actually relatively simple. See: #1908910-33: View links are not displayed (rendered) in menu.