Background
I’ve used a good number of CMSs over the years and all seem to have advantages and disadvantages. In the area of creating a site menu, I usually hard-code it in Expression Engine. Various posts and tutorials mention that most of the time, once a menu is created, there’s not much need to alter it, so hard coding is good enough, easy to do and less taxing. That might be true, but sometimes a client just needs the ability to add static pages and set their menus as they see fit.
I’ve been away from the ExpressionEngine community since 1.6 so I feel behind the curve with the new 2.x features. The 3rd party market has also exploded. Still, out of the box, I find the lack of an easy manner to create static pages and setup menu structure a pain. Especially after working with WordPress. (Heck, even the early versions of Joomla made this process easy.) I’m aware that EE concept has always been to target to developer and experienced designer vs the WordPress ‘end-user’ target.
I’m currently using EECore 2.6 since I’m not really ready to commit to upgrading my old 1.6 license to the full version of 2.7. Perhaps some of the functions in the full-version would make my life easier!
Plug-ins for navigation & structure
As I mentioned, it is cool to see so many 3rd party products, both free and premium available for EE. I reviewed many plugins which provide a ‘WordPress’ approach to building pages and site menus. They all look very cool. However, I’m keen to setup a menu system without a plugin. (Nothing against plug-ins.)
Getting Started
It’s been awhile since I touched EE and I have forgotten a great deal. I was never a professional user (I don’t do web pages for a living.) The two methods I will cover are probably used by many developers and nothing new. Most likely, due to my skill level, they may not be the most efficient way. I’m posting this tutorial because I spent a great deal of time googling this topic and not getting very far.
I started by working my way through the excellent tutorials on Train-EE.com. Mike has five methods for creating navigation for a site. The last method (D) that he presented seemed to be just what I needed however, it uses Reverse Related Entries and from what I understand, because 2.6 has a re-written relationship module, it won’t work. Still, it was a great starting off point.
Method 1
I started this method as I reflect on a very old version of Joomla. The top level menu of the site I dubbed ‘sections’. Anything within a section I dubbed ‘content’. You can attached different names in your mind if you.
Section +Content +Content Section +Content +Content +Content Section +Content and so on….
For example, under the section called ‘About us’, I have 4 content. About us +History +Board of Directors +Community Outreach +Subsidiaries
In Train-EE’s tutorial, Mike used one Channel to represent all static pages. In the above, I am using two channels: Section, Content
I created a field group: Field Group ‘section’ {content_pages} = relationship, relate it to ‘content’ channel {body_content} = text field to hold our html (text). …add other custom fields as you require
I assigned both channel Section and Content to use the field group ‘section’ I created my Section entries. In my case, I created 4 overall site sections. Next, I created the content pages that would be filed under these sections. Once that was done, I went edited all of my Sections. This time, as my Content entries were made, I could now assign them. So on the left you will see your relationship field called Content Pages. Check the ones you want to assign to the Section. They will appear on the right. You can re-order them as well!
The next step is to create a template group. I called it ‘section’ to keep it all consistent.
<ul>
{exp:channel:entries channel="section" sort="asc" dynamic="off"}
<li><a href="http://{path=">{title}</a></li>
{content_pages}
{if content_pages:count==1}<ul>{/if}
<li><a href="http://{path=">{content_pages:title}</a></li>
{if content_pages:count==content_pages:total_results}</ul>{/if}
{/content_pages}
{/exp:channel:entries}
{exp:channel:entries channel="section|content" limit="1" sort="asc"}
<h2>{title}</h2>
{body_content}
{/exp:channel:entries}
</ul>
Paste the above into the index template. If you named any of your channels or fields differently, you will need to adjust them in the code. All this template does is create an un-ordered list of your menu. It’s going to run a loop through all your Sections.
<li><a href="http://{path=">{title}</a></li>
The above will create the <li> element to display one of your Sections. Next, we need to see if that Section has any Content, if it does, we will create a nested list. We start by asking if this is the first time to do this? Since it is, we will insert the start <ul> tag:
{if content_pages:count==1}<ul>{/if}
The next <li> will output your Content name and link. To close the nested loop, we ask if this is the last Content within the Section, if it is we output the closing </ul>.
The second loop in the template is simply to show you that we are displaying the right content related to the menu that we are on. You don’t need that if the template will be simply for navigation. All it does is to look at entry we are on for channel Section and Content, and display the title of the page and the body content.
Based on the template above, you will send up with URLs like this (assuming you removed the index.php from the URL). www.domain.com/section/name-of-section-1 www.domain.com/section/name-of-section-2 etc That’s not bad. But when you go to the Content level (ie the 2nd-tier menu), you also get: www.domain.com/section/name-of-section-1.1 www.domain.com/section/name-of-section-1.2
In other words, no matter what level you are at in the menu, it will include ‘section’ in the URL. You could use htaccess to remove that as you might have with index.php
I created a new template group called ‘content’.
<ul>
<li><a href="http://{path=class=active">Home</a></li>
{exp:channel:entries channel="section" sort="asc" dynamic="off"}
<li><a href="http://{path=">{title}</a></li>
{content_pages}
{if content_pages:count==1}<ul>{/if}
<li><a href="http://{path=">{content_pages:title}</a></li>
{if content_pages:count==content_pages:total_results}</ul>{/if}
{/content_pages}
{/exp:channel:entries}
{exp:channel:entries channel="content" limit="1" sort="asc"}
<h2>{title}</h2>
{body_content}
{/exp:channel:entries}
</ul>
It does the same thing at the other template, just the paths are tweaked.
For example, with a menu like… Members +Volunteer
On Members (a Section), I get: www.domain.com/index.php/section/members and on Volunteer (a Content), I get: www.domain.com/index.php/members/volunteer
Again, using htaccess, we would now have a nice… www.domain.com/members www.domain.com/members/volunteer
Now we are looking like WordPress!
One other thing I tried with this method was to create template groups with the name of the Section.
So I created a template group called ‘About’ I suppose the advantage here is that you could customize the page specific for the content of your About pages. But I want to stay away from needing to explain to a client how to create template groups.
I created this method a few days ago so hopefully I explained it well. I would love to hear ways how I can optimize this.
Method 2
As with the previous method, this approach has probably been done a million times in this community and probably in a better manner. And I should repeat, one of the many plug-ins probably allows for much better control and sanity! After completing Method 1 in creating a menu, I realized that sometimes, you want to have a menu choice that doesn’t display content, instead, it links to a certain page inside or outside of your site. I also started to consider that it would be nice to order the menu as I would like. A further idea would be to allow me to decide WHERE my menu would get displayed. For example, I might have a menu in the top nav, the main menu, the sidebar and the footer. But I am getting ahead of myself….
I created two channels: Menu and Pages. Call them what you want. I was inspired by a hybrid of WordPress and Joomla.
I created a field group, and also called it Menu {menu_order}, Text Input {menu_alias}, Relationships, using channel Pages {menu_children}, Relationships, using channel Menu {menu_link}, Text Input
I created a field group for Pages. I only created one field to hold the content.. {page_body}, textarea (and whatever fields you need)
Assign the two custom field groups to their respected channels.
Now you are ready to create your pages (Pages Channel). Create them in any order that you wish. This time around, I actually created a page called ‘Home’
Once you have your pages made, it is time to assign them to your menu. Let’s work on a menu for the page About Us. The title can be anything. It can be About Us, About, About Our Company. You name it. What is nice is if the page itself is called ‘About Our Great Cool Company’, you can make a simple menu title called ‘About’. Leave the URL Title field alone.
For Menu Order field, give anything that will be at the TOP LEVEL a number starting with 1. Let’s say my top level menu picks are… Home, 1 About, 2 Products, 3 Support, 4 Contact, 5
Should your client want to make Contact appear before Support, just flip their Menu Order. Nice.
The Menu Alias will be a drop down and you will select which Page you wish this Menu to represent. As with Method 1, I have kept my menus to a two-tier level. You may need to tweak the code if you want to go down to 3 or more tiers.
For Menu Children, you will see a list of all your Menus. Check the Menus which should be the children (underneath this menu). The beauty is that you can re-order the children over on the right side.
When you create the Menu for a child Menu, it is important to leave the Menu Order as 0 (zero). ONLY your top-level menu needs a value 1 or greater.
Once your menu is completed, create a template group. I called mine MENU. Paste into index:
<ul>
{exp:channel:entries channel="menu" sort="asc" orderby="menu_order" dynamic="off" }
{if menu_order !=0}
<li><a href="http://{url_title_path=menu}">{title}</a></li>
{menu_children}
{if menu_children:count==1}<ul>{/if}
{menu_children:parents field="menu_children"}
<li><a href="http://{menu_children:url_title_path=menu}">{menu_children:title}</a></li>
{/menu_children:parents}
{if menu_children:count==menu_children:total_results}</ul>{/if}
{/menu_children}
{/if}
{/exp:channel:entries}
</ul>
{exp:channel:entries channel="menu" limit="1" sort="asc"}
<h2>{menu_alias:title}</h2>
{menu_alias:page_body}
{/exp:channel:entries}
The code isn’t too different from Method 1. We are going to spit out an un-ordered nested list and then display the page’s title and content. First thing we will do is check to see if the Menu we are looking at is not equal to 0. So if it is 1 or above, that means it is one of our top-level menus. We will output the top level menu name and make it linkable. Next, we will see if this link has any children. The loop works like Method 1.
The downside of this method is all my menus appear as…. http://www.devserve.com/menu/about http://www.devserve.com/menu/history etc. I can take out ‘menu’ from the URL for a cleaner URL. But this doesn’t show any hierarchy between the first and second tier menus. I’m sure with greater EE knowledge, I can get it to do the same as Method 1, but I’m pretty tired at the moment.
One thing I didn’t talk about was the field: {menu_link} My template doesn’t have the code in place but basically, where you are going to output menu link, check to see if {menu_link} is empty. If it isn’t, use that as the hyperlink instead. You now can link to areas in your site or to a specific page.
I also mentioned displaying your menus in different locations. Just create a menu_location with a drop-down, and when you go to output the menu, check to see if you selected the drop down and if you did, output it, otherwise don’t. And so you can have certain items how up in different places. Role in Statuses and you could also limit who can look at the menu item.
I hope these two tutorials were somewhat helpful. I might be the worse EE coder in this forum. It was an interesting exercise. It’s made me realize the power of EE, but also made me realize that something KISS is just better so I may just go with a hardened install of WordPress in the end (or PyrosCMS.)
p.s. I WOULD LOVE to get tips to optimize or expand on anything presented. Thanks!
Packet Tide owns and develops ExpressionEngine. © Packet Tide, All Rights Reserved.