Chapter 10: Building Page Titles and Setting Navigation Active State Dynamically
In Chapter 9, we finally moved off the Home page of our mock business site and implemented the About page.
The job isn't quite done, however, as neither the page title up in the browser title bar nor the main navigation indicates that we've moved off the Home page. We'll fix that in this chapter by using more Embed Variables for Embedded Templates.
Let's tackle the titles first. The overall approach is very similar to how we implemented the section intros in Chapter 7. We want to pass a variable containing the desired page title to the Embedded Template that holds our HTML header. So we need to:
- Modify each parent template and specify what we want the page title to be (passing the note again).
- Modify the embeds/html_header template to receive the note and display the contents of the variable.
Modifying the HTML Header Template
You'll want to reference the EE User Guide on Embedding Templates within Other Templates because it's helpful for showing how your code needs to be formatted. It can be found at:
For our site, you'll need to edit the title HTML in embeds/html_header by adding the Embed Variable in between the tags. I've named my variable "my_page_title". Before editing you should have:
<title>{site_name}</title>
After editing it should be:
<title>{site_name} | {embed:my_page_title}</title>
Alternatively, you can choose to code this as:
<title>{embed:my_page_title} | {site_name}</title>
The latter approach is considered better for accessibility and SEO. Here's the
entire updated embeds/html_header template for your reference:
Template Name: embeds/html_header
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/ html;charset=iso-8859-2" /> <meta name="author" content="free-csstemplates.com" /> <link rel='stylesheet' type='text/css' media='screen' href="{stylesheet='site/stylesheet'}"/> <title>{site_name} | {embed:my_page_title}</title> </head> <body> <div id="content">
Companion Files: chapter_10/embeds/html_header.txt
Modifying the Page Templates
Now that we have the embeds/html_header template setup to receive the variable, we need to modify the site/index and about/index templates to send the desired page title. You need to edit the very first embed statement, and add your variable name and value onto the end of it.
Before editing, the code is:
{embed="embeds/html_header"}
After editing, the code for the Home page is:
{embed="embeds/html_header" my_page_title="Home"}
And, the code for the About page is:
{embed="embeds/html_header" my_page_title="About"}
Text versions for both the updated site/index and about/index templates can be found in the Companion Files for this chapter (but we're not done with them yet so keep reading).
Once you've made those edits and saved your changes, you should be able to move between the Home and About pages and see the browser title bar change.
Granted, this is a pretty simple implementation of dynamic page titles. As we get another layer deeper into the site (like specific product pages, etc), we'll have to put more code into the embed statements to get the desired page title. More than just static text, we can also use dynamic EE tags like {exp:channel:info} or {exp:channel:entries} for this purpose. But, that's down the road and this will suffice for now.
Dynamic Navigation Styling
The other, more visual, issue with the results from Chapter 9 was that the main navigation still indicated we were on the Home page although we had navigated to the About page. If you look at the HTML for the main navigation, you'll see that the tabs of the design are triggered by applying class=”selected” to the one you want to be active.
So, the question is, how do we both keep our main navigation as one Embedded Template but still provide the proper class to set the active tab in different areas of the site?
Essentially the idea is to use Embed Variables along with ExpressionEngine conditionals to set a variable in each parent template that tells embeds/page_header which item to apply the selected class to. We need to:
- Modify the site/index and about/index templates.
- Modify the embeds/page_header template.
Modify the Page Templates
This is very similar to the process explained above, where we added variables for the page titles. The only difference here is the text we're entering as the value of the variable will never be displayed on the site - it's just something for the conditional in the Embedded Template to work with.
Starting with the site/index template, we currently have the following code that pulls in the main navigation:
{embed="embeds/page_header" the_url_title="home-page"}
This needs to change to:
{embed="embeds/page_header" the_url_title="home-page" my_location="home"}
The about/index template is currently:
{embed="embeds/page_header" the_url_title="about"}
This needs to change to:
{embed="embeds/page_header" the_url_title="about" my_location="about"}
Modify the Page Header Template
The page templates now send a total of two variables to embeds/page_header. The first variable tells embeds/page_header which section intro to pull and the new second variable will tell the main navigation which item to apply the selected class to.
You could use one Embed Variable for both purposes as long as the section intro and selected main nav item will always be used together. I want to allow pages that are deeper in each section to use a different section intro, so I'm choosing to use two Embed Variables. There is no limit to the number of Embed Variables that you can pass from a parent template to an Embedded Template. This capability can make for very flexible Embedded Templates.
The embeds/page_header template now needs to be modified to change the HTML depending on what the contents of the my_location variable. Per Derek's approach we'll put a conditional within each list item. Since we pass only one value, only one of these will ever evaluate as "true," so only one active class will be applied.
The conditional we will use is:
{if embed:my_location=='home'} class="selected"{/if}
This conditional will look at the value of the passed-in Embed Variable. If that variable contains the word "home", then the class="selected" text will be included in the rendered page. If the Embed Variable isn't "home", then no extra code will be rendered out.
We'll use a variation of the conditional for each list item in the main navigation by changing the value the conditional is looking for each time.
Here's the updated code for embeds/page_header:
Template Name: embeds/page_header
<div id="title"> <h1><span class="green"><a href="{homepage}">{site_name}</a></span></h1> <span id="slogan">A Tutorial Series from Trainee.com</span> </div> <div id="menu"> <div class="submit"> <ul> <li><a{if embed:my_location=='home'} class="selected"{/if} href="{homepage}" ><span>Home</span></ a></li> <li><a{if embed:my_location=='about'} class="selected"{/if} href="{path='about'}"><span>About</ span></a></li> <li><a href="#"><span>Products</span></ a></li> <li><a href="#" ><span>Services</span></ a></li> <li><a href="#"><span>Weblog</span></a></ li> <li><a href="#"><span>Contact</span></ a></li> </ul> </div> </div> <div id="subheader"> <div class="rside"> <div class="padding"> <div id="search"> <form action="#" method="get"> <p><input type="text" name="search" size="20" maxlength="250" class="text" value="" /> <input type="submit" value="" class="btn1" /></p> </form> </div> </div> </div> <div class="lside"> <div class="padding"> {exp:channel:entries channel="misc_content" limit="1" dynamic="no" disable="categories|member_data|pagination" url_title="{embed:the_url_title}" } {page_body} {/exp:channel:entries} </div> </div> </div>
Companion Files: chapter_10/embeds/page_header.txt
You have to be a bit picky with the spacing - mainly so that when the conditional evaluates to "false" and the active class is not applied, you don't get extra spaces in your rendered linking code.
See the Companion Files for the updated site/index and about/index templates - chapter_10/index.txt and chapter_10/about/index.txt.
The Results
With these changes made to your templates, you should be able to switch between the Home and About pages and have the page titles and active tabs update as expected.
Figure 33: About Page with Proper Active Navigation
Not Working?
If your Home and About pages aren't loading with unique page titles and the selected class applied to the right main navigation item, here are some things to check:
- Make sure your Embed Variable names match in both the parent template and the Embedded Template.
- Make sure you've used braces and not parentheses in your code.
- Make sure you've used double equals in your conditional - {embed:my_location}=='home' and not a single equals sign. ExpressionEngine is a bit like PHP code in this regard.