Storing menu structures in DB

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Storing menu structures in DB

Post by allspiritseve »

We currently create our menus based on our page hierarchy. However, I've had situations with clients before where they want some pages shown on the menu, while not showing others. Sometimes they want to link to static pages within the site. I'd also like to start adding more types of content than just pages. In general I'm trying to make things a bit more flexible, so I'm considering making a completely separate hierarchy structure for menus. I started coding, and ran into some walls, so I wanted to run this by you all and see if anyone's done this before and has some advice.

The easiest thing to do would be to store the url of each content item at it's location on the menu. I'm hesitant to do that though,as it seems like it would be really easy to have menu items get out of sync with the content. A better approach seems to be to link menu items to content based on ids. However, that would require an intermediate table that stores the content id AND the content type (kinda clunky) and each url would have to be generated on the fly (caching could help here).

So... does anyone here have a separate hierarchy for their menus? How do you link the menu items to the content?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Storing menu structures in DB

Post by Christopher »

I'm not sure why you need an intermediate table that stores the content id AND the content type? It seems like the content type would be stored with the content.

I have done something similar to this in the past, but I rebuilt the menu HTML every time they edited the menu on the admin side. That's usually what I do because there are many, many fewer edits than requests to view the menu. The data in the DB just organizes everything for editing, turning items on/off, etc.
(#10850)
User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Re: Storing menu structures in DB

Post by allspiritseve »

arborint wrote:I'm not sure why you need an intermediate table that stores the content id AND the content type? It seems like the content type would be stored with the content.
Well, if I've got a table of pages, a table of articles, a blog, and a contact page, I can't just link to them by id because there might be conflicts.

I suppose generating the menu html would solve some of these problems.

Edit: I think I'm leaning towards keeping the url with the menu items in the DB. It's the simplest thing I can come up with, and will still allow html tweaks if needed. I'll just need to make sure they don't get out of sync with the actual content if the url changes.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Storing menu structures in DB

Post by Christopher »

allspiritseve wrote:Well, if I've got a table of pages, a table of articles, a blog, and a contact page, I can't just link to them by id because there might be conflicts.
But don't you have to do separate joins against each table?
allspiritseve wrote:Edit: I think I'm leaning towards keeping the url with the menu items in the DB. It's the simplest thing I can come up with, and will still allow html tweaks if needed. I'll just need to make sure they don't get out of sync with the actual content if the url changes.
I think that sounds easiest. You need to keep it in sync, but it gives to more control.
(#10850)
User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Re: Storing menu structures in DB

Post by allspiritseve »

arborint wrote:But don't you have to do separate joins against each table?
Yeah, I'd have to... I have to distinguish a page id of 10 from an article id of 10, somehow. It's hard to treat all content the same unless you have an EAV-type solution (or you just ignore the content and use the generated urls, as I'm going to do).

I'm still open for hearing any other solutions though... it seems like a common enough requirement.
Yossarian
Forum Contributor
Posts: 101
Joined: Fri Jun 30, 2006 4:43 am

Re: Storing menu structures in DB

Post by Yossarian »

I bet they would like to change the order of things as they appear on the menus too?

How about turning things round.

They start with a blank menu and add items in the order they want to see them appear, whats the betting they even want to change the menu labels too.

E.g. lay down an ini file for the menu item called "Our company"

Code: Select all

 
[Our company]
About us = /blog/2007/09/01/about-us
T&Cs = /articles/123.htm
Contact = /pages/contactus.htm
 
The problem is that each new article/blog/page no longer appears automatically in menus, unless you have a hierarchy of menus, some controlled manually from pick lists of available content, and others which are generated automatically.
User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Re: Storing menu structures in DB

Post by allspiritseve »

Yossarian wrote:I bet they would like to change the order of things as they appear on the menus too?
Oh, of course. I think I'm going to do the same thing, just in a database table. The only downside is I have to make absolutely sure that everywhere a URL is changed, the corresponding menu item(s) are changed too.
Yossarian wrote:The problem is that each new article/blog/page no longer appears automatically in menus, unless you have a hierarchy of menus, some controlled manually from pick lists of available content, and others which are generated automatically.
Yeah, for smaller sites I will have menu items added automatically. Ideally I can figure out a seamless way to manage content, locations (which construct urls) and menu items simultaneously, so clients don't even realize they exist until they need to change one separately from the others.
User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Re: Storing menu structures in DB

Post by allspiritseve »

Now, a more theoretical question: should I ever allow menu hierarchies to differ from the content hierarchy?

I'm sort of torn.
  • On one hand, I'm noticing that things get really confusing if there are two hierarchies. My instinct is that from a usability perspective, a menu should be representative of the content hierarchy.
  • On the other hand, clients will request (and have requested) exceptions to that rule.
Any words of wisdom on the subject?
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Re: Storing menu structures in DB

Post by matthijs »

It's those exceptions that make you want a more flexible setup, in my experience. So no strict coupling between content hierarchy and menu.

For example, you have build a site and included a forum. The forum is not a single page in the hierarchy of the pages, but a completely separate module. Now say you want the link to the forum appear inside the menu somewhere:
-home
-about
-news
-forum
-articles
--article1
-- article2
etc
Everything else is a regular page. In this case you want the flexibility to create the menu in a custom way.

If you look at Wordpress templates, they also have a fairly flexible way of handling this. You just have a wp-list-pages() function, with a couple of parameters, one of which is child_off=
That way it's easy to pull out all kinds of (sub) menu's.
User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Re: Storing menu structures in DB

Post by allspiritseve »

matthijs wrote:The forum is not a single page in the hierarchy of the pages, but a completely separate module.
True, but I'm looking at the content hierarchy from a url perspective, so a forum is treated the same as a page:

Code: Select all

/home/
/about/
/news/
/forum/
/articles/
/articles/article/
/page1/page2/page3/
To build a menu from this, all I would have to do is find all top-level content (home, about, news, forum, articles, page1), allow sorting and display toggle, and loop through a list of links. That would be a strict coupling between the content hierarchy and menu.

On the other hand, lets say a client wants page3 to be located under /about/... the actual page is located under /page1/page2/, but the user clicking on it will think they are going to /about/page3/. Now, lets say, for arguments sake, the client doesn't want to write content for the /about/ page (contrived example, I know), but they have several pages beneath it . To remedy this, I want to list all child pages. Should I include page3 in that list? It technically isn't located under /about/, but since the client wanted it located there on the menu, the user will place it there hierarchically. That would be a loose coupling between the content hierarchy and menu.
User avatar
kaisellgren
DevNet Resident
Posts: 1675
Joined: Sat Jan 07, 2006 5:52 am
Location: Lahti, Finland.

Re: Storing menu structures in DB

Post by kaisellgren »

What I do is that I have "pages" in the application. Each page can contain any amount of content associated to it. So, a menu link will make the browser to go to ?page=x basically. The menu items are stored in the database using either Adjacency List Model or Nested Set Model. If you use Views then it does not matter that much.

Personally I do not like the idea of creating the HMTL on the ACP, because it makes the template part of the application. I prefer for having a template for the menu that explains how does the menu look like. You would of course cache the final output of the menu so that you have eliminated any parsing overhead.

And what comes to treating forums as pages, I would just allow the person on the ACP to define an absolute URI for menu items, such as /forum to access the forum.
User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Re: Storing menu structures in DB

Post by allspiritseve »

kaisellgren wrote:What I do is that I have "pages" in the application. Each page can contain any amount of content associated to it. So, a menu link will make the browser to go to ?page=x basically. The menu items are stored in the database using either Adjacency List Model or Nested Set Model. If you use Views then it does not matter that much.
How do you attach content to the pages? Does every blog post have a page?
kaisellgren wrote:Personally I do not like the idea of creating the HMTL on the ACP, because it makes the template part of the application. I prefer for having a template for the menu that explains how does the menu look like.
What's an ACP?
kaisellgren wrote:And what comes to treating forums as pages, I would just allow the person on the ACP to define an absolute URI for menu items, such as /forum to access the forum.
So you have a mix of both menu items and pages that act as menu items? How do you pull that from the database?
User avatar
kaisellgren
DevNet Resident
Posts: 1675
Joined: Sat Jan 07, 2006 5:52 am
Location: Lahti, Finland.

Re: Storing menu structures in DB

Post by kaisellgren »

allspiritseve wrote:How do you attach content to the pages? Does every blog post have a page?
One way would be to make everything into modules/plugins. Basically, you could edit content and place it on a text module and the admin can then choose what pages display what modules. E.g., he could combine several text modules into one page or reuse some text modules.
allspiritseve wrote:What's an ACP?
Admin Control Panel, a place where the site owner modifies his website (the menu, for instance).
allspiritseve wrote:So you have a mix of both menu items and pages that act as menu items? How do you pull that from the database?
Pages do not act as menu items. Pages are simply a way to refer to a set of content / modules / plugins. If you go to site.com/contact, then through mod_rewrite you will get that "contact" part which is the page name. In your database, the pages table has "name varchar(255) not null,primary key(name)" or something similar. In this case the name is the identifier, because it is the one that is being referred to. Then you could put content into modules, and the user can choose what modules are shown in which pages. E.g., the page Home would contain modules "text_welcome", "text_short_about" and "plugin_shoutbox". The text modules are simple content modules and the plugins are more complex.

The point of this system is to separate Pages, Modules/Plugins and Menu Items. This is pretty much versatile. Menu items can point to any pages they want. They can even point to the same page, or not point to certain pages (pages that are not in the menu and can be only found by entering the right URL or crawling the site). Another thing is that this way you could reuse same content and show it in another pages. The same shoutbox can be shown in Contact, Home, wtvr pages. It also makes the creation of drafts easier. For instance, if you want to create content, but not yet publish - don't tell the menuitem and pages to look for it and it will not yet be displayed anywhere.

I'm not sure if you understood, I am not much of an explainer.
User avatar
allspiritseve
DevNet Resident
Posts: 1174
Joined: Thu Mar 06, 2008 8:23 am
Location: Ann Arbor, MI (USA)

Re: Storing menu structures in DB

Post by allspiritseve »

kaisellgren wrote:Pages do not act as menu items. Pages are simply a way to refer to a set of content / modules / plugins. If you go to site.com/contact, then through mod_rewrite you will get that "contact" part which is the page name. In your database, the pages table has "name varchar(255) not null,primary key(name)" or something similar. In this case the name is the identifier, because it is the one that is being referred to.
OK, so you're saying the page defines the url, but somewhere you have a separate menu item with a url /contact/? I think what I'm trying to figure out is the best way to manage separate menu items like that. I've used CMSs before where you had to set the page name, the page title, the headline, and the menu text all at once, when 99% of the time they are all the same thing. At the moment I'm having one field generate all of those, but I need to figure out what to do when one differs from the other, since it may not be useful to link them all at that point.
kaisellgren wrote:I'm not sure if you understood, I am not much of an explainer.
Kietos, I understood very well.
User avatar
kaisellgren
DevNet Resident
Posts: 1675
Joined: Sat Jan 07, 2006 5:52 am
Location: Lahti, Finland.

Re: Storing menu structures in DB

Post by kaisellgren »

allspiritseve wrote:OK, so you're saying the page defines the url, but somewhere you have a separate menu item with a url /contact/? I think what I'm trying to figure out is the best way to manage separate menu items like that.
Hmmh. I am not sure if I understood correctly, but do you mean that if you want a menu link to go to URL /contact/ instead of a page?
Menu Text : URL
----------------------
Home : http://site.com/Home
About : http://site.com/About
Forums : http://site.com/Forums
As you can see, the menu does not need to know what is in there. It just takes you there. If the Home/About/wtvr pages is found, then PHP will display it. Otherwise, it displays a 404 error page. If you want the user to go to that *real* URL, then set an exception into the .htaccess mod_rewrite code. Modifying .htaccess on the fly is almost always possible, if it is not, then obviously all queries will go through the mod_rewritten URL... in which case you could allow a non-mod_rewrite version of your application that works like this:
Menu Text : URL
----------------------
Home : http://site.com/index.php?page=Home
About : http://site.com/index.php?page=About
Forums : http://site.com/Forums
And this would work regardless of whether mod_rewrite exists or not.

A typical WordPress installation:
Pages:
Home
About


Modules:
Archives
Login
RSS/XML/wtvr
Blog Entries

About (Text Module)

Menu Items:
Home
About
As you can see, Pages != Menu Items. The system would work something like this:
Home (Menu Item) -> Home (Page) -> tpl (Template of Home -page) {Archives, Login, RSS, Blog Entires}
About (Menu Item) -> About (Page) -> tpl (Template of About -page) {About}
Where the template tells how the modules are being shown (basically "where").

Maybe you can omit some ideas from this now.
Post Reply