/ 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

24 Comments

  1. 1. By Tracy Osborn on 28th Feb ’08 at 13: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 00: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 00: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 11:32am

    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 3rd Mar ’08 at 20:52pm

    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 05:54am

    An even better solution would be:

    <code>

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

    </code>

  7. 7. By Leon Paternoster on 8th Mar ’08 at 21:56pm

    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 8th Mar ’08 at 23:56pm

    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 01: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 12: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 06:27am

    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 06:30am

    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 14: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.

  14. 14. By Jon Brown on 6th Aug ’08 at 15:04pm

    Love you website’s design and content of course.. great article!-- I used your code inside a php include file for a sidebar menu.. here is a snippet:

    <?php if ($page == 'Visa-B1') { ?>

    <p align="center">B-1: Business Visitor</p>

    <?php } else { ?>

    <p align="center"><a href="Visa-B1.php">B-1: Business Visitor</a></p>

    <?php } ?>

    <?php if ($page == 'Visa-B2') { ?>

    <p align="center">B-2: Visitor for Pleasure</p>

    <?php } else { ?>

    <p align="center"><a href="Visa-B2.php">B-2: Visitor for Pleasure</a></p>

    <?php } ?>

    <?php if ($page == 'Visa-E1') { ?>

    <p align="center">E-1: Treaty Trader</p>

    <?php } else { ?>

    <p align="center"><a href="Visa-E1.php">E-1: Treaty Trader</a></p>

    <?php } ?>

    etc..etc.. about 14 items?

    My knowledge of PHP is in EXTREME infancy, so my question is this: for a menu with this many items, is there not a way to do this to decrease the php processing… Is there not a way to set it up so that when the $page condition has been met, it skips the rest the php if-thens.. so I guess to do this if the condition has been met it would not just display that one menu item but all the menu items, plus the live one. But isn’t the whole key to drop out after the condition has been met? And would this not help in the processing time for 14 items?

    Thanks!

  15. 15. By Jon Brown on 6th Aug ’08 at 16:16pm

    Well, in reference to my above comment, after doing a little research, I think what I am getting at is multiple elseif’s (or using the switch statement?) with each containg the full code of the 14 menu items, with one being live.. then that would achieve to lessen the php processing no?

  16. 16. By Ivo Ivanov on 20th Nov ’08 at 16:55pm

    Thanks Jon,

    this was a very useful tutorial for a graphic designer like me:)

  17. 17. By v1nk on 28th Dec ’08 at 05:23am

    Thank you soo much for this code!

  18. 18. By David Jacobs on 20th Jan ’09 at 22:00pm

    This was very helpful. You made it short and sweet. Thank you so much.

  19. 19. By Johnnie on 11th Aug ’10 at 18:03pm

    Many thanks for this informative and very useful tutorial!

  20. 20. By Volkov Alex on 20th Aug ’10 at 02:35am

    This example have very much checks (if) and this will be slowly.

  21. 21. By Tom Prior on 2nd Sep ’10 at 13:41pm

    I’ve always been apprehensive about dipping my toe into PHP for fear there would be too much learning to do up-front before I could do the simple stuff.

    Your tutorial has not only saved me a lot of time (I’ve just implemented it into my new portfolio site which is going live soon), but also sparked my interest in learning a lot more!

    Thanks

    Tom

  22. 22. By Mark Primavera on 28th Feb ’11 at 12:37pm

    Great tutorial - I have been looking for this for a long time - keep in mind I am still learning PHP.

    I did this for the nav.php (just showing the 'Home' link)

    <code>

    <div class="right-nav">

    <ul class="links sub-nav">

    <?php if ($page == 'home') { ?>

    <li class="parent"><a href="#" class="selected">Home</a>

    <ul>

    <li> <a href="#/">Link 1</a></li>

    <li> <a href="#">Vestibulum tincidunt </a></li>

    <li> <a href="#">Vacancies</a></li>

    <li> <a href="#">Lorem ipsum dolor</a></li>

    <li> <a href="#">Policy committee</a></li>

    <li> <a href="#">We always remain flexible</a></li>

    <li> <a href="#">Aenean at felis a leo</a></li>

    <li> <a href="#">Remuneration committee</a></li>

    </ul>

    </li>

    <?php } else { ?>

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

    <?php } ?>

    </code>

  23. 23. By K.P. on 11th Oct ’12 at 04:06am

    Thank you. I’ve just started a new project using Bootstrap for the first time and I’ve been struggling with the active menu for a couple of days because I wanted the menu as an include rather than editing every page. Your solution works perfectly.

  24. 24. By M. Slack on 31st Jan ’13 at 15:29pm

    This is fantastic! I wish I would have found this sooner!

    Thank you.

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. Anakin Tue, 26th Jun 2012 {4}

    I’m pleased to be able to say that Analog is joining forces with…

  2. We, Who Are Web Designers Mon, 19th Sep 2011 {65}

    In 2003, my wife Lowri and I went to a christening party. We were friends…

  3. Ampersand, the Aftermath Wed, 22nd Jun 2011 {3}

    The first Ampersand web typography conference took place in Brighton last…

  4. Design Festival, The Setup, and Upcoming Posts Mon, 20th Jun 2011 {1}

    Wow, this has been a busy period. I’m just back from the Ampersand…

  5. Web Design as Narrative Architecture Wed, 30th Mar 2011 {12}

    Stories are everywhere. When they don’t exist we make up the…

  6. Ides of March Tue, 15th Mar 2011 {4}

    My friend and colleague, Chris, has shared a spiffing idea, the Ideas of…

Remarks from the log

  1. By ilkyaz reklam in Typeface != Font:

    as a teacher in graphic software. Your article explenation is perfectly clear http://ilkyazreklam.com

  2. By Otomatik Rent A Car in Seven Things:

    I can empathize with the book. The image of a tiny kayak with a man http://otomatikrentacar.com

  3. By Otomatik Rent A Car in Seven Things:

    I can empathize with the book. The image of a tiny kayak with a man http://otomatikrentacar.com

  4. By Otomatik Rent A Car in Seven Things:

    I can empathize with the book. The image of a tiny kayak with a man

  5. By DarkStar in Smoothing out the Creases in Web Fonts:

    I agree with Leicester that table is great!

  6. By Martin Varesio in Ampersand, the Aftermath:

    His dry, droll, richly-flavoured delivery was a humorous counterpoint to some controversial asides…

People and XFN

Analog folks:

  1. Andrei Zmievski

  2. Chris Shiflett

  3. Jon Gibbins

Friends, colleagues, and authors with interesting voices:

  1. Ben Ramsey

  2. Dan Mall

  3. Denna Jones

  4. Ed Finkler

  5. Elizabeth Naramore

  6. Elliot Jay Stocks

  7. John D. Boardley

  8. Helgi Þormar Þorbjörnsson

  9. Joe Leech

  10. Jos Buivenga

  11. Kester Limb

  12. Nicola Pressi

  13. Patrick H. Lauke

  14. Piotr Fedorczyk

  15. Richard Rutter

  16. Rick Hurst

  17. Sean Coates

  18. Simon Pascal Klein

  19. Terry Chay

Live the questions and one day grow into the answers.