ColdFusion custom tags allow you to build a flexible template for your site that will feed every page on the site. Part 1 of this series showed the basic concepts of the custom tag and how to use one as a site template. The tutorial addressed the setup and implementation of a custom tag, and showed how to supply a title to the document dynamically. Part 2 showed you how to add other features to this template, such as JavaScript, CSS, and meta tags. Part 3 will show how to incorporate a table layout or a div layout in setting up your template.

Warning: If you are following the tutorial in Dreamweaver MX, you should be aware that Live Data view will cause a page that uses a custom tag in this way to become corrupted. Stay away from Live Data view when dealing with ColdFusion custom tags.

The Template

To follow along with this part of the tutorial, you will have needed to complete the first part of the tutorial and the second part of the tutorial. Feel free to try out the examples using the included files.

We left off with a custom tag template (mytemplate3.cfm) that looked something like this:

<cfparam name="attributes.title" default="Community MX">
<cfparam name="attributes.scripts" default="">

<cfif thistag.executionmode EQ "start">

<!--- Start tag contents here --->
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<cfinclude template="#request.mypath#/includes/mystyles.cfm" />
<cfinclude template="#request.mypath#/includes/meta.cfm" />
<cfinclude template="#request.mypath#/includes/myscripts2.cfm" />
<title><cfoutput>#attributes.title#</cfoutput></title>

</head>

<body>

<cfelse>
<!--- End tag contents here --->
</body>
</html>
</cfif>

If you recall in the last installment, we were using site-relative paths in all of our include files. This is because even though the custom tag is located in one location, the pages that call the custom tag could be located anywhere. For that reason, page-relative paths will not work. In the code above, I've introduced a variable--request.mypath. This allows you to use site-relative paths in any file in your site without worrying about setting up mappings in the ColdFusion administrator or in your web server. The variable is set up in the Application.cfm file. If you download all of the files for this tutorial to a folder called sitetemplate in your root web application, you'll have to adjust the path in the Application.cfm file to reflect this:

<cfset request.mypath = "/sitetemplate" />

The string should have a preceding slash character, making it a site-relative path, but no trailing slash. If your folder is named communitymx/sitetemplate, your variable would look like this:

<cfset request.mypath = "/communitymx/sitetemplate" />

If you are using a site template like this at the root of a site, your variable would be empty:

<cfset request.mypath = "" />

This gives you great versatility in creating custom tags for your site. The tag can be used from any file within the site and all of the include file paths, script file paths, and css include paths should work. Just keep in mind that anything you use that has a path in it should also use this variable:

<cfinclude template="#request.mypath#/includes/styles.cfm" />

The next step is to incorporate a page layout to the template. I'll show how you might set up a typical table layout, and then move to a typical CSS layout with <div> tags.

Using a Table-based Layout

Table-based layouts have an advantage in some situations where your users will have older browsers. Following is a typical table-based HTML skeleton page:

<table id="maintable" width="100%" cellspacing="0" cellpadding="0" >
  <tr>
    <td><div align="right">My Logo Goes Here</div></td>
  </tr>
  <tr>
    <td>
      <table id="contenttable" width="100%" cellspacing="0" cellpadding="0" >
        <tr>
          <td width="20%"><cfinclude template="<cfoutput>#request.mypath#</cfoutput>/includes/menu.cfm"></td>
          <td width="80%">My content goes here</td>
        </tr>
      </table>
    </td>
  </tr>
  <tr>
    <td><div align="center"><cfinclude template="#request.mypath#/includes/footer.cfm"></div></td>
  </tr>
</table>

The main table (id="maintable") is a 3-row 1-column table that contains a logo in the first row, a footer in the third row, and a nested table in the second row. The nested table is a simple 1-row 2-column table that contains navigation in the first column, and the main content in the second column. The first column contains a <cfinclude> that is a simple menu navigation. The second column is where our main content for each individual page will go. The table structure will go into the ColdFusion custom tag, and the page calling the tag will supply the content that goes into the table cell labeled "My content goes here".

When you are creating templates like this, you have to think differently about opening/closing tags. Our ColdFusion custom tag, as you recall, had the opening <html> and <body> tags in the open tag, and the closing </body> and </html> tags in the close tag. The same principle will apply here for the table. Everything up to -- and including -- the open <td> tag for the page content ("My content goes here") will go into the custom tag open tag, and everything starting with the </td> closing tag to the end of the table will go into the custom tag closing tag.

Take the ColdFusion custom tag named mytemplate3.cfm and copy it. Name the copy mytemplate4.cfm and put it in the mycustomtags directory. We'll add the table layout to the tag. The result is as follows:

<cfparam name="attributes.title" default="Community MX">
<cfparam name="attributes.scripts" default="">

<cfif thistag.executionmode EQ "start">

<!--- Start tag contents here --->
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<cfinclude template="#request.mypath#/includes/mystyles.cfm" />
<cfinclude template="#request.mypath#/includes/meta.cfm" />
<cfinclude template="#request.mypath#/includes/myscripts2.cfm" />
<title><cfoutput>#attributes.title#</cfoutput></title>

</head>

<body>
<table id="maintable" width="100%" cellspacing="0" cellpadding="0" >
  <tr>
    <td><div align="right">My Logo Goes Here</div></td>
  </tr>
  <tr>
    <td>
      <table id="contenttable" width="100%" cellspacing="0" cellpadding="0" >
        <tr>
          <td width="20%"><cfinclude template="#request.mypath#/includes/menu.cfm"></td>
          <td width="80%">

< cfelse>
< !--- End tag contents here --->
</td>
        </tr>
      </table>
    </td>
  </tr>
  <tr>
    <td><div align="center"><cfinclude template="#request.mypath#/includes/footer.cfm"></div></td>
  </tr>
</table>

</body>
</html>
</cfif>

The page that we'll use to call this template is called tagtest4.cfm, and contains the following code:

<cfimport prefix="mytag" taglib="mycustomtags">
mytag:mytemplate4
 title="Using a table based layout"
 scripts="validate.js,utility.js">
<h1>This is a test of our template</h1>
<p>Any sort of content can go in the page now. The custom tag opening and closing tags are now acting as our HTML &lt;body&gt; tags</p>
</mytag:mytemplate4>

The page is basically the same page as tagtest3.cfm, with a minor change of the name of the tag (mytemplate4). If you browse the page, you should see the content displayed inside the table cell of the new custom tag:

Figure 1 -- Table layout

This was a simple example, but you can see the concept at work: the content area that changes from page to page is the only content that you have to worry about on your web pages. The rest of the page is supplied by the custom tag.

Using a CSS Layout

By now you have probably figured out exactly how this is going to work. It is just like the table layout above, only we will use a CSS layout with <div> tags holding our content rather than table cells. The sample layout looks like this:

<div id="top">
My Logo Goes Here
</div>
<div id="col1">
<cfinclude template="#request.mypath#/includes/menu.cfm">
</div>
<div id="col2">
My Content goes here
</div>
<div id="footer">
<cfinclude template="#request.mypath#/includes/footer.cfm">
</div>

Again, all of the content above "My content goes here" will go in the open tag, and all the content below it will go in the close tag. Using a layer (div) based layout, we also have to include the CSS for the layout. We'll put this into our CSS file, styles/divstyles.css and include it in the template:

body {
  font-size: .8ems;
  font-face: verdana, arial, sans-serif;
  background-color:#FFFFFF;
  color:#000000;
}

#top {
  margin:30px;
  text-align:right;
}

#col1 {
  float:left;
  display:inline;
  margin-left:5px;
  width:20%;
  border:1px solid #DDDDDD;
}

#col2 {
  float:left;
  display:inline;
  margin-left:5px;
  width:75%;
  border:1px solid #DDDDDD;
}

#footer {
  margin-top:30px;
  padding:10px;
  clear:both;
  text-align:center;
}

Again, copy the mytemplate3.cfm and name it mytemplate5.cfm. This will be the basis of the new custom tag for the div-based layout. The final code for the tag will look like this, featuring the new open and close tags, as well as the new stylesheet definition:

<cfparam name="attributes.title" default="Community MX">
<cfparam name="attributes.scripts" default="">

<cfif thistag.executionmode EQ "start">

<!--- Start tag contents here --->
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<cfinclude template="#request.mypath#/includes/meta.cfm" />
<cfinclude template="#request.mypath#/includes/myscripts2.cfm" />
<link href="#request.mypath#/styles/divstyles.css" rel="stylesheet" type="text/css" />
<title><cfoutput>#attributes.title#</cfoutput></title>

</head>

<body>
<div id="top">
My Logo Goes Here
</div>
<div id="col1">
<cfinclude template="#request.mypath#/includes/menu.cfm">
</div>
<div id="col2">

<cfelse>
<!--- End tag contents here --->
</div>
<div id="footer">
<cfinclude template="#request.mypath#/includes/footer.cfm">
</div>

</body>
</html>
</cfif>

Now, the calling page will be identical to tagtest4.cfm, only we'll name it tagtest5.cfm and change the tag inside the file to use the mytemplate5 instead of mytemplate4 (are you seeing the pattern here?).

<cfimport prefix="mytag" taglib="mycustomtags">
<mytag:mytemplate5
title="Using a Div Layout"
scripts="validate.js,utility.js">
<h1>This is a test of our template</h1>
<p>Any sort of content can go in the page now. The custom tag opening and closing tags are now acting as our HTML &lt;body&gt; tags</p>
</mytag:mytemplate5>

If you browse this page, you should see something like this:

Figure 2 -- Div layout

Dynamic Content

Now that you've seen how flexible this technique is with regard to a page layout, we will introduce some dynamic content using dynamic includes inside of dynamically generated <div>s.

The first thing to point out is that ColdFusion is one of the few languages that supports dynamic include files, using <cfinclude>. We can pass an include file reference to the custom tag and use that in a <cfinclude> statement. To make this even more dynamic, we'll allow the user to pass zero or more <cfinclude> files to the page. These files will act as modules inside of our template.

Uses for this technique include things like search boxes, banner ads, login forms, and other types of content that may change depending on some pre-defined criteria. We'll include these files in our left column dynamic content: menu.cfm, banner.cfm, and login.cfm, all located in the includes directory. Once again, just like we did with the dynamic JavaScript includes, we'll pass the filenames to the custom tag from the calling page in a comma-separated list, and loop thru them in our custom tag. The custom tag is a copy of mytemplate5.cfm and will have the <div id="col1"> content replaced by our dynamic content. The custom tag now looks like this, with the new content highlighted:

<cfparam name="attributes.title" default="Community MX">
<cfparam name="attributes.scripts" default="">
<cfparam name="attributes.leftcolumn" default="#request.mypath#/includes/menu.cfm">

<cfif thistag.executionmode EQ "start">

<!--- Start tag contents here --->
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<cfinclude template="#request.mypath#/includes/meta.cfm" />
<cfinclude template="#request.mypath#/includes/myscripts2.cfm" />
<link href="<cfoutput>#request.mypath#</cfoutput>/styles/divstyles.css" rel="stylesheet" type="text/css" />
<title><cfoutput>#attributes.title#</cfoutput></title>

</head>

<body>
<div id="top">
My Logo Goes Here
</div>
<div id="col1">
<cfset divcount = 0 />
<cfloop list=#attributes.leftColumn# index="i" delimiters=",">
<cfset divcount = divcount + 1 />
<div id="leftcol<cfoutput>#divcount#</cfoutput>">
<cfinclude template=#i# />
</cfloop>
<cfloop from=1 to=#divcount# index="i">
</div>
</cfloop>

</div>

<div id="col2">
<cfelse>
<!--- End tag contents here --->
</div>
<div id="footer">
<cfinclude template="#request.mypath#/includes/footer.cfm">
</div>
</body>
</html>
</cfif>

The <cfloop> tag loops through the list that we pass into the attributes of the custom tag, and the variable i will contain the name of the ColdFusion page to include. A count of <div> open tags is made as we go through the loop so that we can create another loop for the closing <div> tags. The calling page will be named tagtest6.cfm and will look like this:

<cfimport prefix="mytag" taglib="mycustomtags">
<mytag:mytemplate6
title="Using a Div Layout with Dynamic Includes"
scripts="validate.js,utility.js"
leftcolumn="#request.mypath#/includes/menu.cfm,
#request.mypath#/includes/login.cfm,
"#request.mypath#/includes/banner.cfm"
>
<h1>This is a test of our template</h1>
<p>Any sort of content can go in the page now. The custom tag opening and closing tags are now acting as our HTML &lt;body&gt; tags</p>
</mytag:mytemplate6>

Once again the changes are highlighted. If you browse the page, you should see something like this:

Figure 3 -- Dynamic div layout

Because the divs are nested, they fall into place one after another and force the footer content down.

Conclusion

In this 3 part series we've addressed the topic of using a ColdFusion custom tag as a template for your entire site. Many sites use this versatile technique to set up pages for parts of sites or entire sites. My own site, www.flash-remoting.com uses this technique, as does Macromedia's Pet Store html example. For more information on ColdFusion custom tags, check out the ColdFusion documentation.