I haven't cut this deeply into drupal before and I'm a bit confused reading the records in my database (menu-custom, menu_links & menu_router).

All I need to do is to get the plain HTML representation of a menu in the proper weighted order. I don't even want to apply classes, except perhaps to the root UL node.

I've poked around the site some without finding anything quite right.

-- Is there a standard drupal function to do this?

-- Is there a code snippet around that I could use?

-- Is there a place in the standard documentation that I missed that covers this?

Any help or advice would be much appreciated.

The problem as I see it is that the following SQL returns a menu in physical database order, and properly nested:

SELECT * FROM dbName.menu_links m
where menu_name = 'primary-links'
ORDER BY 
  p1 ASC, p2 ASC, p3 ASC, p4 ASC, 
  p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC, 
  weight, link_title;

... which is all well and good. But the weight variable is not handled correctly by this approach. (The mlid's in the fields p1 etc take priority in the sort order).

Something more is needed to get the weights properly reflected in the ordering -- at each level of the menu no less.

This is really just a variety of the parts explosion problem, which is common enough, but it's always a bit of a headache to handle economically.

I'm sure this has been handled a thousand ways before by a thousand more experienced drupalists than myself.

I'm hoping one such savvy person reads this and can throw me a line.

Even for just reading this, thanks.

Comments

ss_drupal’s picture

Apparently the following will provide HTML:

	<?php
	$menuTree = menu_tree_all_data('primary-links', NULL);
	$rendering = menu_tree_output($menuTree);
	print($rendering);
	?>

But the HTML is rendered full of classes.

So here's the catch, and maybe it's not proper drupal practice, I want to control those classes, and in fact omit most of them.

Suggestions?

johanbostrom’s picture

Glad I found this thread as I'm looking to do exactly the same thing as you :)
I did this to remove every class from the output, and it works!
I hope you find it useful.

$menuTree = menu_tree_all_data('primary-links', NULL);
$rendering = preg_replace('/\sclass=\"[a-z\s]+\"/', '', menu_tree_output($menuTree));
print($rendering);
ss_drupal’s picture

It seems I have to override the functions theme_menu_item_link and theme_menu_tree. (In menu.inc or possibly in my theme's or base themes template.php).

I imagine the method for doing that is documented somewhere on the site.

Phew!

I still wish there was a shorter way through this.

Help is still invited.

dman’s picture

It certainly looks like you found the answers. Congratulations!
Sorry you didn't get the quick answers when you asked!

The simple, clean way is just to ignore the classes you don't want, tey don't hurt anything. Possibly un-theme them in your CSS. Using firebug will help figure out what to set with you own versions.

ss_drupal’s picture

The only things that still have me stumped are these.

(1) I need to apply a couple of particular classes to the root UL of the tree.

The theme_menu_tree function in menu.inc seems to output EVERY UL in the tree, with the same class="menu" statement.

But even if I override it (which I have successfully tested) I can't for the life of me figure out how to test for the root node.

I suppose I can wait until the page loads and then go back and tinker with the class settings from javascript. (JQuery addClass or something like that). But that seems unclean.

Nulling out the offending classes from CSS would work I suppose, although you are right, they don't seem to hurt anything so far.

(2) The other problem I have is that I don't want to do this on ALL my menus, only on one particular menu. All the functions I've seen seem designed to kick in whenever a menu is built.

Any advice?

BTW: Thanks for reading.

dman’s picture

Menu item rendering does not know its depth which is a PITA.
I've had to either drastically rewrite those menu theme functions to pass a depth counter (which I've done) or do stupid things with CSS to set a property, for ul.menu, then unset it for ul.menu ul.menu and do something else, then unset THAT for ul.menu ul.menu ul.menu
Meh.
I don't know the quick one.

Whatever you are doing, if it's either CSS or Jquery, you can just apply your task to #menublockname ul.menu - rather than trying to change the theme when you are really just changing the style.
in CSS or Jquery again, you can find the top menu items as #menublockname > div > ul.menu (or equivalent)

Those tools are there to be used like that.

ss_drupal’s picture

You make a good point.

Maybe the CSS/javascript approach isn't really sinful. And there are good selectors for what I want to get at.

I have to say that I'm a bit shocked, and sort of grossed out. that after going to all the trouble of being able to specify classes like "leaf first" and "leaf last" that the authors didn't think to provide for something like "menu root" -- or even "menu level0", "menu level1" ...

And yes, I too am accustomed to handling tree data with recursive functions that take a depth parameter.

But what the hey.

I'll give CSS/javascript a try.

Thanks again.

=================

Questions of academic interest:

Do overrides have to have the same prototype as the original function?

For example in the case we've been discussing, function theme_menu_tree takes a single parameter it calls $menu. Could one simple add another parameter to the override like:
function themeName_menu_tree($menu, $depth=-1, $bUseDepth=false)
... would that screw things up in drupal land?

Or is it possible, when doing overrides, to provide two overrides, one for ordinary stuff and one for special cases? (To be used by conditional code in some higher level override that calls out to it.)

I won't need to apply these methods to the issue we've been talking about. The CSS/javascript approach is easier. But I'm still very curious.

In any case, thanks again.

dman’s picture

In order to do what you want there, you'll find that you also have to over-ride some core funcs in order to ensure those new values actually get passed down.
When you trace menu tree building (and it's hard because it's all inside-out and abstracted) you find a call stack like

theme func
> system func
> > theme
> > > system
> > > > theme

Now your custom theme func can't pass its new parameter to the later calls, because the system calls won't do that. So you are stuffed.

However, in extremis, you can get it done by

theme func
> copyofsystem func
> > theme
> > > copyofsystem
> > > > > theme

You need to (IIRC) make your own my_menu_tree_output which will pass those parameters down.
Or maybe it's even trickier - I did it in D5. D6 looks different

ss_drupal’s picture

Interesting and curious, not to mention PITA.

The JQuery trick works like a champ.

BTW I discovered a curious thing, my naivitee I suppose -- once you do a removeClass and/or an addClass, the results don't show in either the browser view source function, nor in firebug.

There doesn't seem to be any way to peer under the hood. So debugging and prepping has to be done the old fashioned way, judging by results and outputs.

=========

I guess I'll have to study the drupal calling stack. Sigh.

I like drupal enormously, it's a very powerful and flexible system, but in matters like this I really regret the missing object oriented stuff.

The codebase doesn't seem to have been designed for ease of maintenance or tweaking. Standard OO methods would be easier to work with than complex and hidden function calling protocols.

Thanks again for your help and advice.

kompressaur’s picture

I hope you dont mind me asking here as i think this is related to what i am truing to do. please go easy on me. Im starting to understand php and html and drupal and css as i go. I have not much knowledge but a lot of time.

Basically i was wanting to change the way the menus for a content type are displayed. I was wanting them like the info box of wikipedia in that they have links horizontally like

link1 - link2 -link3 - link4 -link5 - link6 -
link7 - link8 -link9 - link10 -link11 - link12

The menus are being produced....well i have them in Panels. Bah i dont know. Basically its the Taxonomy Terms in Panels 3. Ive added them with some context i think. I am also using DHTML Menu and just standard Taxonomy i think. Would i edit the content type template and add something to the CSS? all help much appreciated as i dont know wheere to go or what to do next. Firebug describes the menus i want to change as-

<li class="first last dhtml-menu start-collapsed  expanded"><a id="dhtml_menu-2647" title="use this if your adding music stuff" href="/taxonomy/term/434%20399%20435%20330%20405%20376%20485%20479%20423%20486%20323%20419%20436%20437%20351%20312%20331%20438%20424%20385%20439%20332%20398%20440%20487%20425%20488%20441%20352%20480%20292%20408%20400%20442%20313%20426%20489%20382%20481%20422%20417%20333%20407%20353%20443%20427%20444%20357%20377%20334%20339%20386%20340%20324%20445%20428%20314%20446%20387%20409%203">Music Genres</a><ul class="menu" style="display: block;"><li class="leaf fake-leaf"><a id="dhtml_menu-2647" title="use this if your adding music stuff" href="/taxonomy/term/434%20399%20435%20330%20405%20376%20485%20479%20423%20486%20323%20419%20436%20437%20351%20312%20331%20438%20424%20385%20439%20332%20398%20440%20487%20425%20488%20441%20352%20480%20292%20408%20400%20442%20313%20426%20489%20382%20481%20422%20417%20333%20407%20353%20443%20427%20444%20357%20377%20334%20339%20386%20340%20324%20445%20428%20314%20446%20387%20409%203">Music Genres</a></li><li class="first dhtml-menu collapsed start-collapsed "><a id="dhtml_menu-2648" title="Avante-Garde" href="/music-genres/avante-garde">Avante-Garde</a><ul class="menu"><li class="leaf fake-leaf"><a id="dhtml_menu-2648" title="Avante-Garde" href="/music-genres/avante-garde">Avante-Garde</a></li><li class="leaf first dhtml-menu "><a id="dhtml_menu-2649" title="Experimental" href="/music-genres/avante-garde/experimental">Experimental</a></li>
<li class="leaf last dhtml-menu "><a id="dhtml_menu-2650" title="Minimalist" href="/music-genres/avante-garde/minimalist">Minimalist</a></li>
</ul></li>
<li class="leaf  dhtml-menu "><a id="dhtml_menu-2651" title="Blues" href="/music-genres/blues">Blues</a></li>


loads more till.....


<li class="leaf last dhtml-menu "><a id="dhtml_menu-2837" title="World" href="/music-genres/world">World</a></li>
</ul></li>

and then it looks like its this in the css-

.menu li.expanded, .menu li.collapsed, .menu li.leaf {
list-style-image:none;
}
style.css?k (line 577)
ul.menu li {
margin:0 0 0 0.5em;
}
system...s.css?k (line 8)
li.expanded {
list-style-image:url("../../misc/menu-expanded.png");
list-style-type:circle;
margin:0;
padding:0.2em 0.5em 0 0;
}
system...s.css?k (line 11)
li {
margin-left:30px;
}
style.css?k (line 73)
* {
margin:0;
padding:0;
}
style.css?k (line 17)
Inherited fromul.menu
ul.menu {
list-style:none outside none;
text-align:left;
}
system...s.css?k (line 3)
Inherited fromdiv#content.main-content
#content {
font-size:1.05em;
line-height:1.75em;
}
style.css?k (line 345)
Inherited fromdiv#page.clearfloat
#page {
font-size:0.7em;
}
style.css?k (line 154)
Inherited frombody
body {
color:#666666;
font:100% Arial,Helvetica;

I am guessing i would have to make up a new listclass? All help appreciated. I dont mind spending time makign it happen. I just need a few pointers int he right direction. Thanks.