Web site templates

Where are we?

Our first PHP task is an easy one, but one of the most important uses of PHP.

Most Web pages have regions, like this:

Web page regions

Figure 1. Web page regions

Different parts of a page are put into the regions:

Using the regions

Figure 2. Using the regions

All of the pages on a site usually have the same structure. Some regions have the same content. For example, every page might have the same thing in the bottom region. CoreDogs is like this. No matter what page you look at, the bottom is the same.

Well, almost. The message on the right of the footer is chosen randomly for each page.

Suppose you have a Web site with, say, 200 pages. Every page has this in the bottom region:

Original footer

Figure 3. Original footer

Your client (or employer, school, sister, whoever) wants to change it to this, on every page:

New footer

Figure 4. New footer

If each page is a separate HTML, that means you have to change 200 files. Ack! What a pain.

But if you use PHP to set up a template for the site, you can change all 200 pages by just changing one file. You read that right – change the entire site by editing one file!

Talk about a productivity win.

If you use just one thing from this book, make it this one: creating active Web templates with PHP. That’s what you’ll learn in this chapter. And it’s one of the easiest things you can do with PHP.

This chapter’s goals

By the end of this chapter, you should:

One thing to keep in mind: this can get confusing! Not so much because the PHP for Web templates is complex. It’s not. It’s simple, in fact.

The problem is that there are so many pieces to a Web site. HTML files, CSS files, JavaScript files, link tags, image tags, and other things. They all need special treatment.

For this chapter to make sense, you’ll need to know how Web sites are put together. I’ll assume that you’ve worked through the ClientCore book, and more-or-less understand it. You should know about images, links, nav bars, CSS files, JavaScript files, a little jQuery, and page layouts.

Let’s get started!

PHP outputs HTML

This lesson’s goals

By the end of this lesson, you should:

  • Know that Web servers embed PHP output in HTML.
  • Be able to use PHP’s print statement.

What’s the time, server?

Let’s take a look at a simple PHP program. It will show the time on the server. This is quite likely to be in a different time zone from the one you’re in, but that’s OK.

To begin, click here. A new window (or tab) opens, and a page shows with the time on the server.

Now look at the page’s URL. It will look something like this:

http://coredogs.com/content_media/lessons/servercore/web-site-templates/server-time.php

Look at the extension of the file. Usually, we see .html. This one is .php. What’s the difference?

When a Web server gets a request for a URL, it looks at the extension to figure out what to do. Here is the process for an HTML file.

Get an HTML file

Figure 1. Get an HTML file

The browser sends a request for x.html to the server (1). The server looks on its hard disk, and reads the file (2). It sends the data it read back to the browser (3).

You can read about the details on the page Static Web pages.

But when the URL ends in .php, the server does something else.

Get a PHP file

Figure 2. Get a PHP file

The browser sends a request to the server, this time for x.php. The server reads the file from its disk drive (2). The server notices the file has the extension .php, so it sends the data it read to the PHP interpreter (3).

The PHP interpreter is a program that runs on the server, just like any other program. It can follow instructions written in the PHP programming language.

The PHP interpreter follows the instructions in the data it got from the server (4). Most of the time, PHP code is embedded inside HTML code.

The PHP interpreter sends its results back to the server (5). The server sends the data back to the browser (6).

All of this happened when you clicked on a link to http://coredogs.com/content_media/lessons/servercore/web-site-templates/server-time.php. The browser asked the Web server at coredogs.com for the the data at server-time.php (1 in Figure 2). The server read the file server-time.php from its disk drive (2), and passed the file’s contents to the PHP interpreter (3). The interpreter ran the code (4), and gave the results back to the Web server (5). The server then sent the data back to your browser (6).

That’s a lot of stuff happening, just because you clicked a link!

What the browser got

Have a look at the HTML code that the browser got from this page. (In Firefox, hit Control-U. In other browsers, right-click and select View source or Show source, or whatever it says.)

You’ll see something like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Server time</title>
  </head>
  <body>
    <p>The time at the server is 
    04:10:22 PM    </p>
  </body>
</html>

Figure 3. The HTML

It looks just like regular HTML, although the formatting around line 8 is a little strange. There is no PHP or anything here, just plain HTML.

The PHP in the file server-time.php generates normal HTML. The browser can’t tell the difference between a page manually typed in by a person, and one that’s generated. That’s the beauty of PHP; the browser just gets HTML, a language it already understands.

Now click the server time link again. You’ll get a different time, assuming that a few seconds have elapsed. Have a look at the HTML source of the new page. It’s almost the same as it was. Just the time is a little different.

In fact, each time your browser asks for server-time.php, it will get plain HTML, but it will get different HTML (if the requests are at least a second apart). The URL is always the same:

http://coredogs.com/content_media/lessons/servercore/web-site-templates/server-time.php

But the PHP in the file server-time.php creates different HTML each time.

Inside server-time.php

Here’s what’s in the file server-time.php on the server’s hard disk:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Server time</title>
  </head>
  <body>
    <p>The time at the server is 
    <?php 
    print date('h:i:s A');
    ?>
    </p>
  </body>
</html>

Figure 4. server-time.php

Lines 1 to 8 and 12 to 14 are regular HTML. The PHP interpreter just passes them back to the server unchanged. The magic happens in lines 9 to 11.

Let’s make sure we understand what I wanted the page to show. I wanted the server to send back HTML that looked like this:

<p>The time at the server is (time goes here)</p>

When you program in PHP, you are programming indirectly. You write PHP code that creates HTML, or text that gets embedded in HTML. The HTML then gets returned to the browser for rendering. So remember:

You write PHP that writes HTML.

Line 9 is the PHP opening tag: <?php. It tells the PHP interpreter that some PHP is about to appear. The interpreter runs the code until it hits the close tag in line 11: ?>.

Line 10 is:

print date('h:i:s A');

print is a PHP statement that says “Output what follows.” date() is a PHP function that gets the current date and time, and returns it. The stuff in the parentheses (()) is a format, telling date how to show the date and time. In this case, the hours, then a colon (:), then the minutes, then another colon, then the seconds, then a space, and then an AM/PM indicator.

The statement ends with a semicolon (;). All statements in PHP end this way. If you leave off the semicolon, the PHP interpreter will get confused, and complain.

The result? The print statement outputs the current time.

Exercise: Web server time

Upload the server time program on to your own server. One way is to:

  • Copy the code in Figure 4 onto the clipboard.
  • Paste it into a new file in Notepad++ (or whatever editor you use).
  • Save the file. Remember, I recommend you create a new directory for every exercise. For example, you might create a directory called coredogs/servercore/web-templates/server-time, and save the file there. coredogs is this site, servercore is the book on CoreDogs, web-templates is the chapter in the book, and server-time is the exercise in the chapter. It seems like a lot of typing, but it’s very important to keep your files organized.

Name the file whatever you want. If you name it index.php, it will be the default file in that directory. You can read more about default files.

If you installed XAMPP on your computer, and you put the file somewhere under your htdocs directory, you can access it through your browser. For example, suppose you saved the file as:

C:\xampp\htdocs\coredogs\servercore\web-templates\server-time\server-time.php

This is a file path for a Windows machine. If you use a Mac or Linux box, your path will have a slightly different format.

Remember that C:\xampp\htdocs\ is the root of the Web server on your computer.

Make sure your Apache server is running (use the XAMPP control panel to start it). In your browser, type the URL:

http://localhost/coredogs/servercore/web-templates/server-time/server-time.php

http://localhost/ maps to C:\xampp\htdocs\. The rest of the path maps to your PHP file.

Once the program works, upload the file to your hosting account, and point your browser there. (If you didn’t install XAMPP on your computer, you will need to upload the file before you can test it.) I recommend that you use the same file structure on your hosting account that you used on your own computer.

Now, change the page. Add an <h1> that says something like:

Renata’s first PHP program

Of course, replace Renata with your own name.

Upload the new version. Enter the URL of your first PHP program below.

(Log in to enter your solution to this exercise.)

Can't find the 'comment' module! Was it selected?

Exercise: Show IP addresses

Write a PHP page that will show the IP addresses of your browser, and the server the page is running on.

You can get the IP addresses with:

$_SERVER['REMOTE_ADDR']

$_SERVER['SERVER_ADDR']

Hint: base this on the server time example.

You can run my solution.

Upload your solution to your server. Put the result below.

(Log in to enter your solution to this exercise.)

Can't find the 'comment' module! Was it selected?

Summary

  • When a Web server gets a URL with a .php extension, it sends the file to the PHP interpreter.
  • You embed PHP code in HTML pages.
  • Most PHP code outputs HTML, which then gets sent to the browser for rendering.

What now?

Outputting stuff will help you create dynamic Web templates. The next thing you need to know is how to insert one file inside another.

Onward! To glory!

Inserting files

Where are we?

You saw how the print statement puts data into the HTML. Let’s see how you can put entire files into the HTML.

This lesson’s goals

By the end of this lesson, you should:

  • Know how to use PHP to insert a file into the HTML output.
  • Know how to use a file path to insert the same file in pages that are spread out across a directory tree.

Inserting files

PHP has several statements that insert files: include, require, and require_once. We’ll just talk about one of them: require.

Suppose we create a file that contains HTML to show a footer for every page on a Web site. Here it is:

<div id="footer">
  Copyright © 2010  |  All rights reserved
</div>

Figure 1. Footer code.

This is not a complete HTML page, just a fragment of HTML. It wouldn’t work by itself. Let’s call the file footer.inc. The .inc reminds us that the file is meant to be included in another file.

Here’s the PHP page include-footer.php:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Including a footer</title>
  </head>
  <body>
    <h1>Hi there!</h1>
    <p>I am a page. Aren't I wonderful?</p>
    <?php 
    require 'footer.inc';
    ?>
  </body>
</html>

Figure 2. Including a footer

The require statement reads the file it’s given, and inserts it. Any PHP in the included file is executed. If the PHP interpreter can’t find the file, it shows an error message.

You can try it. Make sure you have a look at the HTML source. As far as the browser knows, the content of footer.inc was typed directly into include-footer.php.

Inserting files from other directories

The code in Figure 2 is in a file called include-footer.php. It has the line:

require 'footer.inc';

There is no directory given, just a file name. So where will the PHP interpreter look for footer.inc?

The answer: in the same directory as include-footer.php. So if include-footer.php is in /my/directory/of/doom/, then the PHP interpreter will look for /my/directory/of/doom/footer.inc.

When you’re using dynamic Web templates for real, this won’t work very well. Suppose you were creating a site with this structure:

Site structure

Figure 3. Site structure.

The file at /index.php is the home page of the site. The file at /articles/index.php shows a list of articles. There are other things like blog entries, products, and so on, but we don’t need to consider them here.

Suppose you put this line into both /index.php and /articles/index.php:

require 'footer.inc';

You would need one footer.inc for /index.php and another for /articles/index.php:

Duplicate footer files

Figure 4. Duplicate footer files.

But what’s the point of that? If we wanted to change the footer text across the entire site, we’d have to change all of the footer.inc files.

What we really want is for both /index.php and /articles/index.php to refer to the same footer.inc.

Just one footer file

Figure 5. Just one footer file.

footer.inc is in a directory called library. PHP developers often move shared files to a directory like this, and call it library, lib, includes, common, or something like that.

But we have to change the require statements to make this work. Here is the require statement from /index.php:

require 'library/footer.inc';

Here is the one for /articles/index.php:

require '../library/footer.inc';

The .. means “go up a level.”

To brush up on how to use paths to navigate between directories, see the discussion of absolute, relative, and root relative links.

An example

Let’s see how this would work in an entire Web site.

Let’s create a simple site called The Dog Site. It has a home page and two sections: dog profiles, and articles.

Overview

Figure 6. Site overview.

Each of the two sections of the site – dog profiles and articles – has a main page. Each one is linked from the home page.

Here is the home page:

Home page

Figure 7. Home page.

Here is the main page for the dog profile section:

Dog profile main page

Figure 8. Dog profile main page.

Here is the main page for the articles section:

Articles main page

Figure 9. Articles main page.

You can try the site.

Let’s create the directory tree for the site, that is, the directories on the server that all the files will go into. We’ll make a directory for each section of the site: dog profiles and articles.

The header is the same on every page, so let’s pull that out and put it in its own file. Here’s the code:

<!-- Header file, to be included into every page. -->
<h1>The Dog Site</h1>
<h2>Bringing you happiness since last week</h2>
<hr>

Figure 10. HTML for the header.

Let’s put the code into the file header.inc, and put the file into a library directory.

Here is the directory tree so far.

Initial tree

Figure 11. Initial tree.

The home page is index.php. Recall that if a browser sends a URL to a Web server, and the URL does not have a file name, then the browser uses a default name. In ClientCore, we used index.html as the default. index.php can be the default as well.

So if a browser asks for:

http://dogthing.com/play/

the server will run:

http://dogthing.com/play/index.php

Let’s see what the tree looks like when all the files are added:

Complete tree

Figure 12. Complete tree.

All of the PHP files are going to have a require statement, to insert header.inc. But since the PHP files are in different directories, they will use different paths to navigate to header.inc. Here are the paths for some of the files.

File Path in require
/index.php library/header.inc
/articles/index.php ../library/header.inc

Figure 13. Paths in some of the files.

Exercise: The rest of the paths

Complete figure 13. Give the path in the require statement for every PHP file.

You can check your solution by downloading a zip file of the site. Expand the zip file to see the PHP code.

(Log in to enter your solution to this exercise.)

Can't find the 'comment' module! Was it selected?

Exercise: Inserting files

Download and expand this zip file. It will create a directory tree like this:

Directory tree

Figure 1. Directory tree

Open up wombat.php. Add require statements to create a page that looks like this:

Output

Figure 2. Output

Use only relative file paths.

Upload the entire tree to your server. Put the URL below.

You can see my solution, but try it yourself first.

(Log in to enter your solution to this exercise.)

Can't find the 'comment' module! Was it selected?

Summary

In this lesson, you learned:

  • How to use PHP to insert a file into the HTML output, using the require statement.
  • How to use a file path to insert the same file in pages that are spread out across a directory tree.

What now?

But there’s a problem. It’s easy to break links to images and other resources. Let’s fix that in the next lesson.

Inserting files with links and images

Where are we?

You’ve seen how to use the require statement to insert one file into another. But do it the wrong way, and your site won’t work. Let’s look at the problem and a solution.

This lesson’s goals

By the end of this lesson, you should:

  • See how inserting files can break images, links, and other paths in your site.
  • Be able to fix the problem with a PHP variable.
  • Understand why this is a Big Win.

The dog site

Let’s look again at the dog site. Remember that it has two sections: articles and dog profiles. Here’s the directory tree:

Directory tree

Figure 1. Directory tree

The file header.inc is inserted in all of the other PHP files. For example, here’s how it is inserted into playing-with-dogs.php:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Playing with dogs | The Dog Site</title>
  </head>
  <body>
    <?php 
    require '../library/header.inc';
    ?>
    <h2>Article: Playing with dogs.</h2>
    <p>Pretend there is some content here.</p>
    <p><a href="index.php">Back to the article list</a></p>
  </body>
</html>

Figure 2. Code for playing-with-dogs.php

Line 9 inserts a header file that is the same across the entire site. The path says “go up to the parent directory, then down into the library directory, then insert the file header.inc.”

Here’s the header:

<!-- Header file, to be included into every page. -->
<h1>The Dog Site</h1>
<h2>Bringing you happiness since last week</h2>
<hr>

Figure 3. HTML for header.inc

You can try the site. You can also download a zip file with all of the PHP and other files.

The client wants to add the following logo to the header of every page:

Logo

Figure 4. Logo

“No problem,” we say. We put the image file (logo.png) in the library directory.

Logo in the library directory

Figure 5. Logo in the library directory

We change header.inc to:

<!-- Header file, to be included into every page. -->
<h1><img src="logo.png" alt="Logo">The Dog Site</h1>
<h2>Bringing you happiness since last week</h2>
<hr>

Figure 6. First try at the new header.inc

But this doesn’t work. Look at the home page. You’ll see something like:

Broken logo

Figure 7. Broken logo

Exactly what you see depends on how your browser handles broken image links.

So what’s the problem? Tell your browser to show you the HTML of the page (Control+U, or right click), and you’ll see:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Welcome | The Dog Site</title>
  </head>
  <body>
    <!-- Header file, to be included into every page. -->
<h1>The Dog Site</h1>
<h2><img alt="Logo" src="logo.png">Bringing you happiness since last week</h2>
<hr>    <p>Welcome to the dog site.</p>
    <p>See some <a href="dog-profiles/index.php">dogs</a>.</p>
    <p>Read an <a href="articles/index.php">article</a>.</p>
  </body>
</html>

Figure 8. HTML of index.php with broken logo

Again, the layout is a little strange around line 9, because the HTML here is inserted by PHP.

Line 10 contains the logo HTML. It’s exactly what we put into header.inc. So what’s the problem?

It has to do with the directory that logo.png is in. The file is in the library directory (See Figure 5). But the browser gets this code:

<img alt="Logo" src="logo.png">

There is no path, just logo.png. So the browser tries to load the image from the same directory that index.php is in.

index.php is in the root directory of the site (/). So the browser tries to load /logo.png.

Oops.

Every page on the site has the same problem. For example, /articles/why-dogs-are-great.php also has the line:

<img alt="Logo" src="logo.png">

inserted by the PHP require statement. The browser tries to load logo.php from the same directory as why-dogs-are-great.php. So it tries to load /articles/logo.png.

Argh!

How to fix it?

One choice is to copy logo.png to every directory, but that’s a really bad idea. If we wanted to change the logo for the site, we’d have to find and change every copy of logo.png.

Root relative URLs

A better choice (but not the best) is to change the inserted code to:

<!-- Header file, to be included into every page. -->
<h1><img src="/library/logo.png" alt="Logo">The Dog Site</h1>
<h2>Bringing you happiness since last week</h2>
<hr>

Figure 9. Root relative path in header.inc

The src attribute on line 2 has changed. It has the full path to the logo. This is a root relative URL. It says “Go to the root of the Web site, then go down into the library directory, then find logo.png.

This works! But…

Root relative URLs cause their own problems. They reduce the portability of a site, that is, your ability to move all of the files in the site around.

Remember that part of CoreDogs is not just learning the tech, but learning to think like a Weber. That is, to understand how people who create Web sites do their work.

On just about every project, you want to have a separate test version of the site. You tell your client “go look at the test version to see what I’m doing.” Then you can talk about changes.

Let’s say you put a test version of the site on http://mytestsite.com/dogsite/. You also have test versions of other sites, like http://mytestsite.com/catsite/ and http://mytestsite.com/hipposite/. This is common Weber practice; keep test versions on different domains from the product site.

But there’s a problem. You’ve moved the files into a directory called dogsite. The root relative path of the logo file is now /dogsite/library/logo.png. Your library file (header.inc) has /library/logo.png. So you have to change it to /dogsite/library/logo.png. Argh!!

But every time you copy the test version of the site to the production version, you have to remember to change back every root relative path. Double argh!!

And you have to do this for every root relative path! Not just the logo, but CSS files, JavaScript files, ...

Triple argh!!!

There are ways around this, too, but the fact is that root relative URLs are a pain.

But there’s a good solution. One that works well for template-based, dynamic Web sites.

Using a root path variable

What we’re going to do is change the HTML code that header.inc inserts. Instead of just src="logo.png", it will insert src="library/logo.png", or src="../library/logo.png", or src="../../../library/logo.png", or whatever each page needs.

We’ll do this by creating a variable on each page, and having header.inc use that variable.

If you remember back to JavaScript, you learned that a variable is a piece of computer memory that’s given a name. For example, here’s some JavaScript that takes whatever the user typed into a form field, puts it into the variable user_name, and tests whether the variable is empty.

user_name = $("#user").val();
if ( user_name == "" ) {
  alert("Sorry, you must enter a user name.");
}

Figure 10. JavaScript variable

PHP has variables, too. They act much like JavaScript variables. One difference is that their names all begin with $ (a dollar sign).

Our solution to the logo problem is in two steps:

  • On every page, create a variable containing the path from that page to the Web site’s root.
  • Use that variable in header.inc.

Let’s have a look. Here’s the directory tree again.

Directory tree

Figure 5 (again). Logo in the library directory

See the file playing-with-dogs.php in the articles directory? Here is the new version:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Playing with dogs | The Dog Site</title>
  </head>
  <body>
    <?php 
    $path_to_root = '..';
    require $path_to_root . '/library/header.inc';
    ?>
    <h2>Article: Playing with dogs.</h2>
    <p>Pretend there is some content here.</p>
    <p><a href="index.php">Back to the article list</a></p>
  </body>
</html>

Figure 11. Code for playing-with-dogs.php

Line 9 creates a variable called $path_to_root. Remember that variables begin with $ in PHP. The string “..” is put into the variable. You can put any characters you like into a variable. You can put numbers, too, and other things.

Notice that the statement ends with a semicolon (;). All statements must have a semicolon at the end. JavaScript is forgiving about this. PHP is not.

Line 10 is:

require $path_to_root . '/library/header.inc';

The period (.) is PHP’s string concatenation operator. It sticks two strings together. So 'Big' . 'ger' would yield 'Bigger'.

JavaScript uses plus (+) to mean the same thing, but if you remember, that causes problems, because + in JavaScript also means “add two numbers together.” PHP doesn’t have that problem. PHP has two operators (. and +) that mean two different things.

Let’s look again:

$path_to_root = '..';
require $path_to_root . '/library/header.inc';

Part of Figure 10 (again). Code for playing-with-dogs.php

.. is the path from playing-with-dogs.php to the Web root. /library/header.inc is the path from the Web root to the header file. Put them together, and you get ../library/header.inc, which is the path from playing-with-dogs.php to the header file.

So far, so w00f. As long as $path_to_root is set correctly for every page, the header file will be found correctly.

Note that this variable is declared in files that other files (like the header) are inserted into. These are the files with require statements, not the files that are inserted by the require statements.

What about the files that are inserted? They use the variable that was declared. Let’s look at the new header.inc.

<!-- Header file, to be included into every page. -->
<h1><img src="<?php print $path_to_root; ?>/library/logo.png" alt="Logo">The Dog Site</h1>
<h2>Bringing you happiness since last week</h2>
<hr>

Figure 12. Code for header.inc

Remember that the print statement outputs stuff into the HTML stream. It can output anything, anywhere. Including file paths!

If $path_to_root has ‘..’ in it, then line 2 will produce:

<h1><img src="../library/logo.png"

As before, $path_to_root has the path from the file that the code in Figure 12 is inserted into, to the Web root. /library/logo.png is the path from the Web root to the logo file. Put them together, and you have the path from the page the header code is inserted into, to the logo.

You can try this version of the site. Look at the HTML for a few pages, and check out the paths to the logo. By the way, you know that “..” means “go up one level to the parent.” “.” means “stay where you are.” You’ll see that on the home page.

You can download a zip file of the site if you want.

This approach works for all paths, whether they’re for images, links, CSS files, JavaScript files, or anything else. To see that, suppose we wanted to add a contact page to the site, with a link from the header of every page:

Link to contact page in header

Figure 13. Link to contact page in header

The contact page is at /contact.php, that is, in the Web root, along with the site’s home page.

Contact page in directory tree

Figure 14. Contact page in directory tree

We can add a contact link to every page on the site by only changing header.inc! W00f!

Here is what the new header.inc would look like.

<!-- Header file, to be included into every page. -->
<h1><img src="<?php print $path_to_root; ?>/library/logo.png" alt="Logo">The Dog Site</h1>
<h2>Bringing you happiness since last week</h2>
<p><a href="<?php print $path_to_root; ?>/contact.php">Contact us</a></p>
<hr>

Figure 15. New code for header.inc

Line 4 does the trick. $path_to_root contains the path from the page the code is inserted into to the Web root. The contact page is right there in the Web root; that’s just /contact.php.

Why this is a Big Win

You see how we could add the contact link by changing only one file? It wouldn’t matter how many pages were in the site. 10? 100? 10,000? Change just one file, and everything gets changed.

This is a Big Win for someone who works on Web sites, especially someone who does it professionally. Webers don’t think just about the end result, that is, the site that users will see. They also think about the work processes that create that site.

Webers think about productivity. The more productive they are, the better value they give employers and clients.

Exercise: Inserting files again

Modify your solution to the first Wombat exercise. Add a variable to wombat.php that has the path to the Web root. Use the variable in all the require statements.

Upload the file to your server. Put the URL below.

You can see my solution, but try it yourself first.

(Log in to enter your solution to this exercise.)

Can't find the 'comment' module! Was it selected?

Summary

  • Inserting files with paths in them – to images, links to pages, whatever – can break your site.
  • You can fix it with root relative paths, but this makes your site less portable.
  • A better way it to create a variable on each page, giving the path from that page to the root of the site. Add that variable in the inserted files.
  • This gives you a big productivity win. You can change an entire site just by changing one inserted file.

What now?

Using a variable like $path_to_root works with all kinds of paths in the HTML. We’ve fixed paths to images (the logo) and links (the contact page) in this lesson.

But there are often paths in JavaScript code. To images, for example. We need to fix them as well. How?

The JavaScript connection

Where are we?

In the previous lesson, we saw how to use a PHP variable to keep links and images working in a dynamic templating system. We got the Big Win of being able to reuse things like page headers on all pages of a site.

Let’s look at reusing JavaScript files. The goal is the same. Have one JavaScript file that’s included across all pages. If we want to change the JavaScript, change that one file, and every page is changed.

This lesson’s goals

By the end of this lesson, you should:

  • See that JavaScript contains file paths. The paths can be broken when inserting files with PHP.
  • See how to fix the problem by creating a JavaScript variable that’s set with PHP.

The problem

Here’s a page with an image and a link.

Sample page

Figure 1. Sample page

Try it, but ignore the Another link for the moment. (We’ll get back to it.)

Move the mouse over the image, and it changes. Move the mouse out, and it changes back. There are two different images. They are swapped in and out when the mouse moves over an <img> tag (more on that later).

Here’s the directory tree for the site.

Tree

Figure 2. Tree

There are two pages. One is /index.html, the one we’ve been looking at. There’s another page, /another/index.html. We’ll get to that later.

The images are in the library directory. The JavaScript that handles the image changing is in the file js-example.js. It’s in the library directory as well.

Why are the files in a separate library directory? Because they’re going to be reused across the site.

Here’s the HTML. No PHP yet.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
    <script type="text/javascript" src="library/js-example.js"></script>
    <title>JavaScript Example - Broken</title>
  </head>
  <body>
    <h1>JavaScript Example - Broken</h1>
    <h2>Home</h2>
    <p><img id="message" src="library/welcome.png" alt="Welcome"></p>
    <p><a href="another/index.html">Another</a></p>
  </body>
</html>

Figure 3. HTML

Look at line 12. There’s the <img> tag that shows the current image. It has an id of message.

The JavaScript that changes the image is in the file /library/js-example.js, referenced in line 6.

(Line 5 is a reference to the jQuery library on a Google server. It uses an absolute URL, and is not affected by the templating system.)

Here’s the contents of /library/js-example.js. This is the JavaScript code that does the image switching.

$(document).ready(function() {
  $('#message').hover(
      function(){
        $('#message').attr('src', 'library/go_away.png');
      },
      function(){
        $('#message').attr('src', 'library/welcome.png');
      }
    );
});

Figure 4. JavaScript

When the mouse goes over the image, the <img> tag shows go_away.png (line 4). When the mouse leaves the image, it’s set back to welcome.png (line 7).

So far, so good. Now try the page again. But this time, follow the Another link. This loads the page /another/index.php. As you can see in Figure 2, it’s in a subdirectory.

The image shows up. But when you move the mouse over the image, go_away.png doesn’t appear. What’s the deal?

It’s the same problem we had on the previous lesson. It’s the file paths. Remember, you’re looking at the file:

/another/index.html

This JavaScript executes:

... attr('src', 'library/go_away.png')

library/go_away.png is a relative path, so the browser looks for the file relative to the current page. It tries to load:

/another/library/go_away.png

But the file is not here.

Argh! Yet again!

You can download all the files from this example.

A JavaScript Fix

Let’s look at a fix that uses just JavaScript, not PHP. It uses a similar approach, though: Set a variable with the path to the root.

Let’s add a few lines to /index.html. This is the first page we saw, the one that worked. Here is the new head section of the page.

  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
    <script type="text/javascript" src="library/js-example.js"></script>
    <script type="text/javascript">
      var path_to_root = ".";
    </script>
    <title>JavaScript Example - Fixed with JavaScript</title>
  </head>

Figure 5. JavaScript fix

Lines 7 to 9 are new. Line 8 creates a JavaScript variable called path_to_root. It’s set with – guess what? – the path from /index.html (the file the code is in) to the root of the Web site. /index.html is in the root directory. “.” means “stay right here.”

We change /another/index.php as well, the page that didn’t work. Here’s what it changes to:

<script type="text/javascript">
  var path_to_root = "..";
</script>

Figure 6. JavaScript fix for another file

The “..” says, “To get to the root, go up to the parent.”

Let’s say we had the file hippo/llama/lion/dog.html. It’s code would be:

<script type="text/javascript">
  var path_to_root = "../../../";
</script>

Figure 7. A long path

dog.html is in the subdirectory lion. Line 8 says, “To get to the root, go up a level, go up a level, and go up a level.”

So, on each page, we create a JavaScript variable with the path from that page to the root of the Web page.

Now, what do we do with that variable? Let’s change /library/js-example.js. Remember that’s the file with the JavaScript code that handles the image switching. Here’s the new code:

$(document).ready(function() {
  $('#message').hover(
      function(){
        $('#message').attr('src', path_to_root + '/library/go_away.png');
      },
      function(){
        $('#message').attr('src', path_to_root + '/library/welcome.png');
      }
    );
});

Figure 8. New JavaScript

path_to_root has the path from the page to the root. /library/go_away.png is the path from the root to the new image file. So:

path_to_root + '/library/go_away.png'

is the path from the page to the new image file.

You can try it. You can also download all the files. Note that everything works just fine.

W00f!

Doing it with PHP

We have a JavaScript line like this, to get the JavaScript code in the library files to work right:

var path_to_root = "..";

We did the same thing in the last lesson, to get the file paths in the library HTML files (like the header and footer) to work right. But we used PHP:

$path_to_root = '..';

We could combine them, and get rid of the duplication. We’d end up with something like this for the head section of a page:

<head>
<?php $path_to_root = '..'; ?>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
  <script type="text/javascript" src="../library/js-example.js"></script>
  <script type="text/javascript">
    var path_to_root = "<?php print $path_to_root; ?>";
  </script>
  <title>JavaScript Example - Fixed with JavaScript</title>
</head>

Figure 9. PHP and JavaScript

Line 4 sets a PHP variable with the root path. Line 9 puts that into a JavaScript variable. With this approach, we only need to remember to set the PHP variable. The JavaScript variable will be set correctly.

/library/js-example.js doesn’t change. The variable it needs – path_to_root – is still set correctly.

For this to work, you need to rename the HTML files, giving them a .php extension. Remember that PHP statements are only executed in files that have the extension .php. Here is the new directory tree:

New tree

Figure 10. New tree

You can try this approach. You can also download the files.

Notice what you are doing here. Look at this again.

<script type="text/javascript">
  var path_to_root = "<?php print $path_to_root; ?>";
</script>

Part of Figure 9 (again). PHP and JavaScript

This puts something like this in the code sent to the browser:

<script type="text/javascript">
   var path_to_root = "..";
</script>

What we are doing is using PHP code to write JavaScript code!

This is so weird. But it’s done all the time. Browsers know how to run JavaScript, just as they know how to display HTML. We take advantage of this. We write PHP that writes JavaScript, just as we write PHP that writes HTML. The browser then does its thing with what we send it.

This is a good example of how computers work in layers. The PHP layer creates stuff for the HTML/JavaScript layer.

Layers

Figure 11. Layers

Each layer has languages it understands. The layer underneath it creates stuff in those languages.

Exercise: Fix the dog head

Try this site with a broken logo animation. Move the mouse over the logo image. It works on the first page, but not the others.

Download a zip file of the site. Fix it, using PHP and JavaScript variables.

You can check my solution and download a zip file of it.

But try it yourself first!

Upload your solution to your server. Put the URL below.

(Log in to enter your solution to this exercise.)

Can't find the 'comment' module! Was it selected?

Summary

  • JavaScript files contain file paths, just like HTML files. The paths can be broken when you use PHP to insert library files.
  • You can fix the problem by creating a JavaScript variable in each file containing the path to the Web root. That variable is added to the JavaScript code in the library files.
  • The JavaScript variable can have its value set by PHP.

What now?

Let’s see where we are.

  • You learned how to insert one file into another with PHP’s require statement.
  • You learned that that causes problems with file paths.
  • You learned how to fix them. Use a PHP variable to store the path from a page to the root. Use that variable in library files, like headers and footers.
  • You learned that reusing JavaScript files can cause similar problems.
  • You learned how to fix them. Set a JavaScript variable from the PHP variable. Use the JavaScript variable in JavaScript library files, like files with nav bar code.

Let’s put this all together, and create a complete dynamic templating system for a Web site.

A complete template system

Where are we?

You know how to use require statements. You know how to use variables to fix broken paths.

Now let’s put it all together. Let’s make a site that has a complete PHP templating system.

This lesson’s goals

By the end of this lesson, you should:

  • Review a site with layout, images, and animated navigation.
  • See how to create a complete PHP template system for this site.
  • Understand the productivity wins this gives us.

Site review

Let’s remake the dog site we looked at a couple of lessons ago. Here is its overall structure:

Site structure

Figure 1. Site structure

There are two sections in the site: dog profiles and articles. The profiles section has profiles of several dogs. The articles section has articles on dog issues.

Here is the home page of the new site.

Home page

Figure 2. Home page

Note that the buttons on the nav bar match the site structure in Figure 1.

The dogs link on the home page, and the dogs button in the nav bar, link to the main page of the dogs section of the site. Here it is:

Main page of the dogs section

Figure 3. Main page of the dogs section

Each link shows a page about a dog. Here’s a sample:

Dog profile

Figure 4. Dog profile

Each dog profile has a photo of the dog.

The other section of the site in Figure 1 is the articles section. Here is its main page:

Main page of the articles section

Figure 5. Main page of the articles section

The page has links to each article. Here’s one of them.

An article

Figure 6. An article

There is one other page: the contact form. A link to it is in the footer of every page. Here it is:

Contact page

Figure 7. Contact page

You can try the site yourself. You can also download the site.

Page layout

Each page has the same layout:

Page layout

Figure 8. Page layout

There are four regions on the page: top, left, center, and bottom. There is no right region in this layout.

The top region has a header. It contains two images (the logo and header image), and some text (a site subtitle). The content of the header – the images and text – is the same on every page.

The left region has a nav bar that is the same on every page. It has three images. The images switch when the mouse hovers over them:

Mouse hover effect

Figure 9. Mouse hover effect

The bottom region has a footer that is the same on every page. It contains some text, and a link to the contact page.

The center region has the main content for the page. It is different for each page.

HTML components

Let’s open up the HTML for a page, and see how it is organized.

HTML organization

Figure 10. HTML organization

Inside the body tag are the four regions. Each has each own div. The colors match the ones in Figure 8.

Figure 10 uses code adapted from the liquid layout in the page layout lesson. The right region was removed, and widths, margins, and padding adjusted.

There’s some more HTML at the start and end of the page. The code at the start gives meta data like title, loads CSS and JavaScript files, and includes any page-specific CSS and JavaScript. The code at the end of the page just closes the body and html tags, although it might do more on other sites.

Remember the PHP!

The HTML for a page is not stored in one file. A key point to remember is that the HTML in Figure 10 is assembled by PHP code.

The HTML is broken up into pieces. Most of the pieces are shared by all pages. The header, for example, is the same across the site (apart from adjusting file paths). The only thing that is completely different for each page is the content.

That’s what gives us the Big Win. There will be one file containing the HTML for the header, no matter how many pages are on the site. 100 pages? One header file. 10,000 pages? One header file.

Change that one file, and every page on the site changes. All 100. Or 10,000. A big productivity win.

Where are we? You’ve seen:

Let’s see what the site’s directory tree looks like.

File organization

Here it is:

Site directory tree

Figure 11. Site directory tree

The root directory of the site just has two files: index.php and contact.php. All of the other files are in directories.

There is a directory for each major part of the site in Figure 1.

Why create a directory for each part of the site? This is another example of how Webers think about productivity. Suppose a user sends this email:

Email about spelling error

Figure 12. Email about spelling error

We want to be able to fix that error quickly and easily. Notice how easy it is to find the file with the error. All the articles are in the articles directory, so go there. The names of the files match the titles of the articles, so we open the file playing-with-dogs.php.

On the other hand, suppose we’d put all of the files in one directory, and named them things like file17.php. It would be harder to find the file with the spelling error.

So the organization in Figure 11 gives us another productivity win. W00f!

OK, back to the files. Here is the tree again.

Site directory tree

Figure 11 (again). Site directory tree

All of the shared files are in library. The file dogsite.css is a site-wide CSS file, with the colors, fonts, page layout style rules, etc. dogsite.js has the JavaScript code for the nav bar image switching.

The .inc files contain the HTML pieces for each page. There’s one file for each chunk in Figure 10:

  • The page start HTML (start_page.inc)
  • The top region HTML (header.inc)
  • The left region HTML (left_nav.inc)
  • The bottom region HTML (footer.inc)
  • The page end HTML (end_page.inc).

We’ll look at the code for each one in a moment.

The rest of the files in library are images for the header and the nav buttons.

Inside the PHP page

Now let’s open up /index.php (the home page), and look at the PHP. Here is the entire code:

<?php 
//Path from this page to the site root.
$path_to_root = '.';
//Title of this page.
$page_title = 'Welcome';
require $path_to_root . '/library/start_page.inc';
require $path_to_root . '/library/header.inc';
require $path_to_root . '/library/left_nav.inc';
?>
<div id="center_region">
  <h1>Welcome</h1>
  <p>See some <a href="dog-profiles/index.php">dogs</a>.</p>
  <p>Read an <a href="articles/index.php">article</a>.</p>
</div>
<?php
require $path_to_root . '/library/footer.inc';
require $path_to_root . '/library/end_page.inc';
?>

Figure 13. PHP for /index.php (the home page)

Line 2 is a comment. Comments begin with //.

Line 3 sets the variable $path_to_root. It contains the path from this file to the site root. /index.php is already at the root, so the variable is set to '.', which means “the current directory.”

Line 5 sets the variable $page_title to, well, the page title. This is used in the title tag, as we’ll see.

Lines 6 to 9 insert chunks of HTML. start_page.inc (line 6) goes down to the body tag. header.inc (line 7) is the page header. left_nav.inc (line 8) is the nav bar.

Line 9 ends the PHP code. Regular HTML follows.

Lines 10 to 14 are the main content of the page, in the center region. This is what varies the most across the pages of the site.

Line 15 starts PHP mode again. Line 16 inserts footer.inc, with the HTML for the page footer. Line 17 inserts end_page.inc, with the HTML to close the body and html tags.

Let’s have a look at /dog-profiles/renata.php, the page showing Renata’s profile. Here’s what it looks like in a browser:

Dog profile

Figure 4 (again). Dog profile

Here’s the code.

<?php 
//Path from this page to the site root.
$path_to_root = '..';
//Title of this page.
$page_title = 'Renata';
require $path_to_root . '/library/start_page.inc';
require $path_to_root . '/library/header.inc';
require $path_to_root . '/library/left_nav.inc';
?>
<div id="center_region">
  <h1>Dog profile: Renata</h1>
  <p>Here is Renata.</p>
  <p><img src="renata.jpg" alt="Renata"></p>   
  <p><a href="index.php">Back to the dog list</a></p>
</div>
<?php
require $path_to_root . '/library/footer.inc';
require $path_to_root . '/library/end_page.inc';
?>

Figure 14. PHP for /dog-profiles/renata.php

Most of it is the same as the code for /index.php, in Figure 13. Let’s look at the differences.

Line 3 has the path to the root. /dog-profiles/renata.php is in a subdirectory, so its path is “..”.

Line 5 has the page title. It is different, of course.

The content for the center region starts at line 10. That’s completely different from page to page, of course.

And that’s it. Those are the only differences.

Notice how easy it is to create a new page. Copy one of the existing pages, change the root path and title, and add the unique content. The header, footer, and nav bar are all set up.

This is another productivity gain. Creating new pages just got a lot simpler.

Let’s look inside the included files.

Here’s start_page.inc, the HTML up to the body tag (see Figure 10).

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title><?php print $page_title; ?> | The Dog Site</title>
    <link rel="stylesheet" type="text/css" href="<?php print $path_to_root; ?>/library/dogsite.css">
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
    <script type="text/javascript">
      var path_to_root = '<?php print $path_to_root; ?>';
    </script>
    <script type="text/javascript" src="<?php print $path_to_root; ?>/library/dogsite.js"></script>
  </head>
  <body>

Figure 15. start_page.inc

The page title is added in line 5. The root path is used in lines 6, 9, and 11. The rest is just plain HTML.

Here’s the code for header.inc.

<div id="top_region">
  <div id="logo_images">
    <img src="<?php print $path_to_root; ?>/library/logo.png" alt="Logo">
    <img alt="The Dog Site" src="<?php print $path_to_root; ?>/library/header.png">
  </div>
  <div id="subtitle">Bringing you happiness since last week</div>
</div>

Figure 16. header.inc

The root path is used on lines 3 and 4, to get the right paths to the image files.

Here is left_nav.inc.

<div id="left_region">
  <ul class="vertical_menu">
    <li>
      <a href="<?php print $path_to_root; ?>/index.php">
        <img id="home_button" src="<?php print $path_to_root; ?>/library/home_up.png" alt="Home">
      </a>
    </li>
    <li>
      <a href="<?php print $path_to_root; ?>/dog-profiles/index.php">
        <img id="dogs_button" src="<?php print $path_to_root; ?>/library/dogs_up.png" alt="Dogs">
      </a>
    </li>
    <li>
      <a href="<?php print $path_to_root; ?>/articles/index.php">
        <img id="articles_button" src="<?php print $path_to_root; ?>/library/articles_up.png" alt="Articles">
      </a>
    </li>
  </ul>
</div>

Figure 17. left_nav.inc

Each link and image needs to be adjusted for the root path.

Here’s footer.inc.

<div id="bottom_region">
  <p>© 2010 Nobody at all  
  |  <a href="<?php print $path_to_root; ?>/contact.php">Contact</a></p>
</div>

Figure 18. footer.inc

The path to the contact page needs the root path. Nothing else changes.

CC
CC

Hey, wait a minute.

Kieran
Kieran

What’s up?

CC
CC

Well, I’m just thinking. This seems awfully complex. Is it worth the effort?

Renata
Renata

Yes, I agree. I’m not sure I’ll like PHP.

Kieran
Kieran

Good point. Let’s talk about that a bit.

The source of complexity

Have a look at the directory tree again.

Site directory tree

Figure 11 (again). Site directory tree

There are lots of pieces here. Look at the library directory. There are fifteen files in there! Ack!

But let’s look more closely. Six of the files are button images. Another two are images for the header region. Nothing to do with PHP there, just regular images.

The files dogsite.css and dogsite.js have nothing to do with PHP either. They’re just regular things we saw in ClientCore.

What about the five .inc files? They are mostly plain HTML. There is only one PHP statement in them: print. As in:

<?php print $path_to_root; ?>

In fact, there is only one other type of PHP statement in the entire site. That’s require, as in:

require $path_to_root . '/library/start_page.inc';

The complexity comes not from the PHP. It comes from the underlying complexity of HTML, CSS, and JavaScript itself.

Web sites are complex. There is no doubt about it. That’s why people pay other people to create them.

The complexity comes not from the fact that any one thing is complex. But even in a small site, there are dozens of things to get right. Each of those small things combines to make a complex whole.

Don’t feel bad if this seems messy to you. It is messy. There’s a lot going on. But it’s your mastery of this that will make you a valuable employee, consultant, or whatever.

And one more thing about complexity. We added the PHP not to make the Web site look better. We added it to make it easier to change. Not only do we have the complexity of HTML, CSS, JavaScript, jQuery, and PHP. We have the complexity of work processes as well.

Ack! It’s enough to drive you to catnip.

The productivity wins

There are some big productivity wins here. Let’s review.

Win: new pages are easy to create

We want a new page, like a new article. We just copy /index.html (or another of the PHP files), change the root path and the title, and add the new content. We just work on what is unique on that new page. We don’t even have to think about the header, nav bar, etc.

Win: making changes in individual pages

Remember the email we looked at earlier, the one that told us about the spelling error? We could find the file to change very easily, because:

  • The directory tree matches the structure of the site, and
  • The file names match the page titles.

This has nothing to do with PHP. It’s just another example of how Webers think. Organize now to reduce problems later.

Big win: making site-wide changes

We can change the entire site by changing one file. For example, let’s say we wanted to add a new section to the site, for products. We add a new button to left_nav.inc, and every page in the site has the new button!

This is a Big Win. Your employer or client will be glad they hired you, because you give good value for money.

Summary

In this lesson, you:

  • Reviewed a site with layout, images, and animated navigation.
  • Saw how to create a complete PHP template system for this site.
  • Read about the productivity wins this gives us.

What now?

Time to do some more exercises.

Exercises: Web site templates

Exercise: Three poets

Create a Web site about three poets, like this one. Use the same method we used in the complete template system.

Download the images from the site.

Upload your solution to your server. Put the URL below.

(Log in to enter your solution to this exercise.)

Can't find the 'comment' module! Was it selected?

Exercise: Old things

Create a Web site about old things, like this one. Use the same method we used in the complete template system.

Download the images from the site.

You can download a zip file of my solution, but try it yourself first.

Upload your solution to your server. Put the URL below.

(Log in to enter your solution to this exercise.)

Can't find the 'comment' module! Was it selected?