/ log / 28th Feb, 2008 /

Designer PHP: A Dynamic Menu with If and Else

Recycling PHP and HTML

In the simple PHP include article I covered how to re-use one file in many pages. If you’re new to using PHP, read that first. Now it’s time to make file includes a bit more useful. In this article, we’ll include one file for main navigation, but make individual menu items “live” depending on the page they appear on.

This is an article in the “Designer PHP” series of guides to using PHP for interface production. Previously:

  1. A Simple Include

To perform this feat, we need to do three things:

  1. Declare a variable on each page to tell the menu what markup to display.
  2. Create a file with “live” and regular markup for each menu item. Add PHP to enable us to switch the markup according to the variable.
  3. Include the menu on every page.

Declare the PHP Variable

The variable declaration must be in every page the menu will appear on. It must be before the line of code that includes the menu so the menu can pick it up. I would normally insert it above the <!DOCTYPE… to separate the PHP from my HTML as much as possible. This is the variable declaration for the home page:

(This variable declaration or PHP statement has two key parts: The variable reference, or name $page, and the variable value "home".)

<?php 
$page = 'home'; 
?>
<!DOCTYPE…
  1. The variable name $page does not change. You can change it to whatever you like, just make sure it’s the same on every page.
  2. The value 'home' will be different for each page to tell the menu what to display.

I usually have the value match the area of the site, so in the example we’re building it will be 'home' on the home page, 'about' on the about page, and so on. You can change the value to whatever you like, and have as many values as you need for individual pages.

Create the Menu File to be Included

For our purposes, we’re going to create a dynamic menu for a fictitious site with three pages: “Home”, “About” and “Contact”. You can extend this to apply to as many pages as you like. This is the basic HTML for the menu:

<div id="nav">
<ul>
<li><a href="index.php">Home</a></li>
<li><a href="about.php">About</a></li>
<li><a href="contact.php">Contact</a></li>
</ul>
</div>

We want two different sets of markup for each menu item: “live” markup and regular markup. In this example we’re going to attach a class to the “live” item — <li class="live"> — and wrap the link in an <em> to differentiate it even if styles are disabled. For example, on the home page, the “live” home menu item will end up looking like this:

<li class="live">
<em><a href="index.php">Home</a></em>
</li>

To switch between “live” and regular markup, we will use PHP “if, and else statements”. This is the menu HTML with PHP:

(White space and line breaks inserted for legibility. PHP is emphasised in red. Disable styles to see it in italics if you need to.)

<div id="nav">
<ul>

<?php if ($page == 'home') { ?>
<li class="live">
<em><a href="index.php">Home</a></em>
</li>
<?php } else { ?>
<li><a href="index.php">Home</a></li>
<?php } ?>

<?php if ($page == 'about') { ?>
<li class="live">
<em><a href="about.php">About</a></em>
</li>
<?php } else { ?>
<li><a href="about.php">About</a></li>
<?php } ?>

<?php if ($page == 'contact') { ?>
<li class="live">
<em><a href="contact.php">Contact</a></em>
</li>
<?php } else { ?>
<li><a href="contact.php">Contact</a></li>
<?php } ?>

</ul>
</div>

Copy the code to a new file in your editor. Save it as nav.php inside an inc directory in your site root.

I have deliberately separated the PHP and HTML as much as possible. There are other ways to achieve the same result, but this removes PHP completely from within HTML tags, hopefully making it easier to read and edit.

Let me explain what the PHP does: Each menu item is marked up in two different ways: the “live” version and a regular version. The variable we declared tells the PHP in the menu which to display. For example, if $page = 'home'; is declared, the if statement ( <?php if ($page == 'home') { ?> ) will display the “live” markup. If home is not declared then the <?php } else { ?> statement takes over, and the regular markup is displayed.

To make any of the other menu items “live”, you adjust the variable. The menu picks it up and switches the HTML. Simple. That’s our menu created and ready for use. The next step is to include it on every page.

Include the Menu

To do this we use the same technique explained in the simple include article, except this time we’re including the menu file, which we’ve called nav.php. This is the PHP you need:

<?php include 'inc/nav.php'; ?>

Insert that in each page at the point you wish the menu to be displayed. The path ( 'inc/nav.php' ) pointing to the nav.php file is relative — make sure you change it if your pages are not all in the site root. Each of your site pages will now look something like this (with the variable value * edited as required):

<?php 
$page='*'; 
?>
<!DOCTYPE… >
<html>
<head>… </head>
<body>

<?php include 'inc/nav.php'; ?>

…content

</body>
</html>

That’s all! Now you can get to the fun bit of styling your menu with CSS. If you need to change anything, you simply edit the nav.php file and every page will be updated. Easy, isn’t it? Let’s end with a few tips about errors and security.

PHP Error Debugging

If you get a heap of PHP errors on a page instead of the menu, the chances are your include file path is wrong. Check it is pointing correctly to nav.php from the location of the page calling it.

It’s useful to know that you can navigate straight to the include file directly in your browser and see the markup.

(E.g. http://yoursite.com/inc/nav.php)

If the file path is wrong, you will get a 404 error.

If no menu items are active, or one is incorrectly active in a certain page, check the variable declared at the top of the page. Does it match the on in the if condition that precedes the item you want “live” in nav.php?

If you’ve done all that, and you’re still having problems, check your syntax line by line. The chances are you’ve missed a tiny mistake. It’s a pain but a good way to learn.

Security

I grabbed a moment with web application security guru, Chris Shiflett to have him check my PHP. This is what he said:

Whenever you’re working with a server-side programming language such as PHP, it’s good to be aware of potential security problems, because a simple mistake is all it takes to create one. If you follow Jon’s example, you’re safe, but what happens when you need to modify it to suit your own unique needs?

Rather than complicate a wonderful tutorial, I’ll just point out that you should research further before doing either of the following:

  1. Add any additional PHP code to your includes.
  2. Use a variable in your include statement, e.g. include "inc/$template".

If you need to do either of the above, you should first read a little more about remote code execution.

Further Reading

Control structures on PHP.net

Can You Translate?

After a wonderful response to the em and elastic layout article, I’d love to hear from anyone who’d like to translate this, or any other article in the series. I’ll be happy to host your work, like the previous Italian translation, or you’re welcome to publish it yourself. Just drop me a line.

Share

Browse More Articles

13 Comments

  1. 1. By Tracy Osborn on 28th Feb ’08 at 21:48pm

    Thank you!

    I spent a year and a quarter in Comp Sci (working with Java) before I switched to graphic design, and I still have trouble with learning Javascript and PHP (I think it’s a mental block…). This was wonderfully simple and completely relevant to web-design, and I look forward to playing with it on my next project!

  2. 2. By inspirationbit on 29th Feb ’08 at 08:16am

    This is a very useful tutorial Jon, and you laid it out so nicely. I hope you don’t mind me chipping in with a suggestion that will make the code shorter and easier to update.

    Rather than using If-Else statements as you've outlined them here, for simple conditional cases like these it’s better to use "short IF statements", that look like this:

    (condition) ? "then part of the code ":" else part of the code";

    So for your example it would look like this (not sure if my code will be displayed correctly in this comment, so I will replace the angle brackets from < and > to *):

    [Ed: Changed to angle brackets]

    ---------

    <?php
    $cssclass = ' class="live"'; 
    //this way if we decide to change the class 
    definition later we can do so in one place
    ?>

    ---------

    then in your HTML section:

    <li <?php echo ($page == 'home') ? $cssclass : "" ?>>
    <em><a href="index.php">Home</a></em>
    </li>

    ----------------------------

    and the same way repeat for all other cases.

    Hope this makes sense. If you could display angle brackets in the comment code, it will make it easier to see the code.

  3. Jon 陳’s profile 3. By Jon 陳 on 29th Feb ’08 at 08:41am

    Thanks Tracey! Let me know how you get on.

    Hi Vivien, thanks, I can see the case for a class variable and welcome the alternative. However, for people new to PHP I don’t think that PHP within HTML tags are easier to read or update, which is why I deliberately chose this technique as I mentioned in the margin note.

    By the way, you can use character entities in your comments for angle brackets if you wish like so: &#60; &#62;. You can also now use <code>…</code> tags, too! we’re working on <pre>. I’ve taken the liberty of inserting angle brackets in your comment for you. Hope that helps. :)

  4. 4. By inspirationbit on 29th Feb ’08 at 19:32pm

    Jon, thanks for updating my code with the angle brackets and for letting me know how I can insert code in my comments here.

    I agree, for the beginners your code is much easier to digest, but then if they want to take it to the next step and make it easier on them to modify its functionality, they could do so with my proposed code above ;-)

    My apologies though – I somehow missed that particular margin note (read the ones before though).

  5. 5. By Nour on 4th Mar ’08 at 04:52am

    Jon,

    I’m really enjoying this PHP for Designers series, keep it up! I actually took a computer course over the summer that touched on PHP, but the instruction was pretty bad and I've forgotten most of it now. Your articles have been very refreshing and will help me in the redesign of my site.

    Looking forward to future installations in the series!

  6. 6. By maZtah on 6th Mar ’08 at 13:54pm

    An even better solution would be:

    <code>

    <li<?php echo ($page == ' home' ? 'class="live"' : ''); ?>>…</li>

    </code>

  7. 7. By Leon Paternoster on 9th Mar ’08 at 05:56am

    Thanks for the article. I’m finding that the include works but the included file doesn’t recognise the $page variable. No error message, just no effect at all. Anyone know why this might happen? Thanks, Leon

    btw – code tags don’t seem to work properly in comments

  8. Jon 陳’s profile 8. By Jon 陳 on 9th Mar ’08 at 07:56am

    Hi mazTah, As I said in an earlier comment, I don’t think that PHP in HTML tags is easier to read or update — that’s an alternative solution, not a better one.

    Leon, if you’re not getting an error of any kind, try checking that the $page variable above the <!DOCTYPE… matches the value in the if() condition before the item you want “live”.

    Code tags are only partly implemented right now. They partly work inline alone, and paired with a parent <pre> for blocks of code.

    They also require that you markup your angle brackets with &#60; / &#60;. It’s not perfect yet, but that’s what happens sometimes when you’re rolling your own apps. :) It bugs me too, but please bear with it, more robust code handling is on the to-do list.

  9. 9. By Leon Paternoster on 9th Mar ’08 at 09:14am

    Thanks for the reply. The variable’s the same in the referring and included files . I echo it at the beginning of the included file, just to see if it’s survived (which it hasn’t). A bit frustrating as it’s my first bit of PHP and it could save me a lot of time (I’m trying to make sure the current selection in the navbar link list doesn’t link to itself, if you see what I mean. I could also change my sidebar content based on the current page – lots of things.) Oh well.

    You don’t use a CMS? Blimey. Isn’t that creating an unnecessary amount of work? I can live without code tags, though.

    Another btw – the text on your site appears to be justified yet you don’t have huge gaps between words. Have you done something to achieve that effect?

  10. 10. By Leon Paternoster on 9th Mar ’08 at 19:43pm

    For reference – for this to work you have to keep the references in the includes relative; using absolute references requires a bit more work (see this forum post.)

  11. 11. By Mis Noma on 21st Apr ’08 at 13:27pm

    Hi, thanks for the article – so helpful!. If I wanted to use png inames for the menu instead of lists how would I adapt the code to add them?

    Say the png’s were home1.png; home2.png and so forth.

    Thanks,

    Mis noma

  12. 12. By Mis Noma on 21st Apr ’08 at 13:30pm

    Hi again, another question.

    If I want the menu to dynamically change just one element of the page, (ie one div for another), and keep everything else (like the background, another menu etc) in place, how would I do that?

    Cheers!

  13. Jon 陳’s profile 13. By Jon 陳 on 21st Apr ’08 at 21:06pm

    Hi Mis Noma.

    If I wanted to use png inames for the menu instead of lists how would I adapt the code to add them?

    If you mean to use images instead of text, simply replace the list items with the image tags as required but don’t forget your alt attributes. :)

    If I want the menu to dynamically change just one element of the page, (ie one div for another), and keep everything else (like the background, another menu etc) in place, how would I do that?

    I’m not sure why you want to do this via the main menu. Optimally, this would be a JavaScript event with all the content printed if JS was not available. See Jeremy Keith’s Dom Scripting book examples for more.

Post a Comment

Required sections are marked § . Please remember, debate and courtesy are mutually inclusive.

Personal Details and Authentication
Comment

Lately in the Log

  1. No. 172 Fri, 4th Jul 2008 {2}

    When I woke this morning it seemed like any other day. The sun was…

  2. The Paragraph in Web Typography & Design Mon, 9th Jun 2008 {15}

    Paragraphs are punctuation, the punctuation of ideas. After selecting a…

  3. Reflecting on Acceptance Mon, 12th May 2008 {15}

    You might already know that my entries are mostly about design with a few…

  4. Typographers, lend me your pain Fri, 2nd May 2008 {13}

    Dear web typographers and designers, I need your help (and your woes!) A…

Remarks from the log

  1. By Peter Gasston in No. 172:

    How funny; I used to live there, and remember many of those places you mention. I lived on Richmond Road, and used to…

  2. By Simon Pascal Klein in No. 172:

    Love the capitalism quote. Congrats mate. What’s the next thing on the list? (;

  3. By James Leicester in Complex Type: CSS Fix, ClearType Miss:

    This is a problem that I have noticed too Jon, I still don’t understand why type rendering looks so bad even on…

  4. By Aphrodizzyac in Designer PHP: A Simple Include:

    Hi there. This all sounds too good to be true – I just wanted to ask if there are any potential disadvantages…

People and XFN

Friends, colleagues and authors with interesting voices:

  1. Jon Gibbins (dotjay)

  2. Alan Colville

  3. Chris Shiflett

  4. Denna Jones

  5. Elliot Jay Stocks

  6. John D Boardley

  7. Kester Limb

  8. Mark Bernstien

  9. Molly E. Holzschlag

  10. Nicola Pressi

  11. Richard Rutter

  12. Terry Chay

  13. Thomas Pinney

Work with me via ~ Grow Collective ~ a creative consortium.