Contemplate: Documentation

##intro

Documentation

These pages roughly follow the sequence of building a website with Contemplate. You can also download our fully functional demo site to experiment with while you learn, or to serve as the basis for a new website of your own.

Quick start

If you're ready to jump right in, here's an overview.

Terminology

Descriptions of the main parts of a Contemplate website.

Site organization

Guidelines for setting up the main folders of your website.

Templates

A complete list of options for embedding content into templates.

Content files

The anatomy of a Contemplate content file.

Page definitions

An explanation of how you can pull it all together.

Preferences

Useful things you can change with the preferences.ini file.

Other components

An overview of the Formulator, Flattener, and Reporter.

Tips and tricks

Miscellaneous goodies that don't fit elsewhere.

Release notes

Complete change histories for each Contemplate component.

Known issues

Things we will change, things we might change, and things we wish we knew how to change.

##quickstart

Quick start

These are the general steps you'll go through in building a website with Contemplate. If you get stuck, click the headings for more detailed explanations of each step.

  1. Download the software
    You can download the latest version of Contemplate, for PHP, ASP, or Perl, here.

  2. Create the main folders for your site
    At the root level of your site, you'll need the following folders: contemplate (the folder you just downloaded), content, and templates.

  3. Design your templates
    You can create templates using any HTML or text editor; just save them as HTML files in your templates folder.

  4. Add embed tags to your templates
    Embed tags are similar to server-side include tags, and tell Contemplate where in the templates to place dynamic content. Here's an example (view the page source to see the embed tags).

  5. Set up your content files
    The most common type of content files is an HTML file with separate pieces of content laid out in a large table. Here's an example.

  6. Define your pages
    A page definition is a series of name/value pairs telling Contemplate which template and which pieces of content to merge together. For the greatest functionality and ease of maintenance, you can list all your page definitions in one shared text file. Here's an example.

  7. Create links to your pages
    Once you have your page definitions, you can create links that call them up at runtime. The most common type of link looks like this: ../contemplate/assembler.php?page=home.

##terminology

Terminology

The first step to building a site with Contemplate is understanding how the different pieces fit together. A Contemplate site consists of templates, content files, the Contemplate scripts, and an optional page definitions file:

Templates

In a Contemplate site, a template is simply an HTML page that contains these references, which use a syntax similar to traditional server-side include tags. We call these references "embed tags," because they let us embed content into a template. You can also think of an embed tag as a placeholder, marking a spot where various pieces of content will appear. The simplest form of embed tag looks like this: <!--#embed footer -->.

Content files

If templates are the domain of the HTML coder, content files are the domain of content writers and editors. The simplest form of content file is a plain HTML file with one large table; each table cell contains one piece of content, which we call a "field." These pieces of content can be as large or small as you like, can contain any HTML tags, client-side, or even server-side scripting, and can be grouped into content files in whatever way is useful for the people maintaining the site. For an example, you can view the content file where this text resides.

On first glance, you might find it odd that many pages worth of content are contained in a single file, but this setup has some big advantages for site editors. Checking files out of a version control system or document repository, making changes, spell checking, uploading, and keeping track of which files have changed are all easier when content is grouped in this way. After all, a 200 page site is much easier to maintain when it consists of only 10-20 rather than 200 files.

Contemplate scripts

The heart of Contemplate is a single server-side script that merges pieces of content into templates in real time to create the pages that the website visitor sees. In addition, the Contemplate package includes scripts that can "flatten" a site, doing all the merging at once and creating static HTML pages; scripts that display easy-to-read summaries of visitor traffic saved by an optional reporting feature; and scripts that help site administrators formulate new pages (new combinations of content and templates) in a direct, visual way.

Now that we've defined the three core elements of a Contemplate site, we can provide an example. You might create a template called default.html and include this embed tag: <!--#embed main -->. Then you might create a content file called content.html that contains several fields, one of which is named strawberry. If you then browse to the URL contemplate/assembler.php?template=default.html&main=field,content.html,strawberry, Contemplate will open the default template, get the strawberry content from the content file, and display it in the spot marked out by the main embed tag.

Dynamic page, long form

Page definitions

Creating pages by passing arguments into templates can quickly become cumbersome, so site developers can optionally pass a single "page" argument into a template instead. Contemplate will look this value up in a shared "page definitions file," where the arguments that define each page are stored. Besides allowing for cleaner URLs, the page definitions file allows you to change a page's composition in one place rather than changing all the links to it site-wide.

Dynamic page, medium form

##organization

Site organization

A typical Contemplate website is organized around three top-level folders: contemplate, content, and templates. The contemplate folder is simply the unzipped source code that you download from this site; content contains your HTML content files; and templates contains your HTML templates with embed tags to show where the content goes. Your page definitions file, if you use one, is normally stored in the contemplate folder.

Contemplate does let you organize your site in different ways or using different folder names. However, if you place content files in another location than a top-level content folder, or templates in another location than a top-level templates folder, then you'll have to specify a relative path to these files in your page arguments. For example, a page definition for a site that uses the default folders might look like this:

template=home.html&middle=field,main.html,home&right=random,tidbits.html

But if you decide to keep your content files in a folder called HTML, the page definition would look like this:

template=home.html&middle=field,../HTML/main.html,home&right=random,../HTML/tidbits.html

As a security precaution, you would also need to tell Contemplate which directories it's allowed to read from. You can list the allowed directories in a preferences.ini file in the Contemplate folder.

You can also organize your site using subfolders rather than storing all your content files or templates into a single folder. For example, to access a template stored in a templates/beta folder, and a content file stored in an HTML/corporate folder, your page definition would look like this:

template=beta/home.html&middle=field,../HTML/corporate/main.html,home

Note that you need to include the ../ in front of the content file because it's stored in a nonstandard top-level folder, but you don't need it in front of the template because that's stored in a subfolder of the standard top-level templates folder.

Aside from the storage locations of your content files, templates, and Contemplate scripts, you can create whatever folders you need to organize your site in the way that works best for you.

##templates

Templates

A template is simply an HTML file with embed tags added to it in the places where you want content to appear. You can use a few different kinds of embed tags for different purposes:

Standard tags

<!--#embed left_column -->
The most common type of embed tag simply says, "Place the piece of content named xxx here." For example, if Contemplate finds the tag <!--#embed left_column --> in your template and the argument left_column=field,main.html,contact_us in your page definition, it will merge the contact_us field from the main.html file into the template file in place of the left_column embed tag.

Hard-coded tags

<!--#embed args=file,header.html -->
If you have an embed tag in a template that will always receive the same piece of content, you can simplify your page definitions by including a reference to that content directly in the embed tag. For example, rather than using the embed tag <!--#embed header --> and including header=file,header.html in your page definition, you can just use the embed tag <!--#embed args=file,header.html -->. We call this a hard-coded tag because you can't pass values for this tag into the template; but you can still benefit from keeping your content in a separate file from your page layout.

Passthru tags

<!--#embed highlight[0] -->
When Contemplate processes a passthru tag, it doesn't go looking for content to display in its place; instead, it simply displays some portion of the page definition. For example, if Contemplate finds the tag <!--#embed highlight[0] --> in your template and the argument highlight=contact_us in your page definition, it will display the text "contact_us" in place of the highlight[0] embed tag.

Passthru tags always include square brackets after the name; this distinguishes them from standard embed tags, and also allows you to access specific elements of a page definition. For example, the tag <!--#embed left_column[1] --> accesses the string "main.html" from the page definition left_column=field,main.html,contact_us. This can be especially useful when adding logic to your templates using client-side or server-side scripts. For example, you could write a PHP script that contains the line $content_file = "<!--#embed left_column[1] -->" and then make the script behave differently depending on what content file the page is reading from.

In addition to accessing every element of the page definition, you can also access the special variables page[0] (the name of the current page), template[0] (the value of the template argument), and page_definition[0] (the complete page definition of the current page). And if you use the "split page names on" preference, you can access specific portions of the page name by setting an index for the page variable. For example, on a page named company_contact with "split page names on: _" in your preferences file, page[1] will return "contact."

If you don't include an index inside the square brackets, Contemplate will return the entire argument or page name. For example, if your page definition includes the argument home=field,main.html,home, then main[2] would return "home" but main[] would return "field,main.html,home." Similarly, if you're splitting page names and accessing individual portions of the page name, you can still access the entire page name with page[].

Combo tags

<!--#embed args=field,lesson+lesson[0],exercise -->
A combo tag is some combination of a hard-coded and passthru tag. This is useful if most of the arguments are the same across multiple page definitions, but they're not all the same. For example, you might be using the embed tags <!--#embed exercise -->, <!--#embed instructions -->, and <!--#embed tips -->, and the page arguments excersise=field,lesson1,exercise&instructions=field,lesson1,instructions&tips=field,lesson1,tips. You could rewrite this to use the embed tags <!--#embed args=field,lesson+lesson[0],exercise -->, <!--#embed args=field,lesson+lesson[0],instructions -->, and <!--#embed args=field,lesson+lesson[0],tips -->, and the page argument lesson=1.

Specifically, a combo tag looks like a hard-coded tag, but you can insert the same values you would use in a passthru tag anywhere in the list of arguments, concatenating with the + sign as needed. Combo tags don't let you do anything that you can't do with the other kinds of tags, but they do let you write simpler page definitions that are easier to read and maintain.

Navigation tags

<!--#embed nav_previous -->, <!--#embed nav_next -->, etc.
If you want to build Next and Previous buttons to page through your site, you can automate this development using Contemplate's navigation tags. For example, if your page definitions file includes these definitions...

home: template=home.html&main=field,main.html,home

joe: template=people.html&main=field,people.html,joe
bob: template=people.html&main=field,people.html,bob
sally: template=people.html&main=field,people.html,sally
sue: template=people.html&main=field,people.html,sue

site_map: template=other.html&main=field,main.html,map

...and you place navigation tags into your template, they would display as follows on various pages:

  page=joe page=bob page=sally page=sue
<!--#embed nav_current --> 1 2 3 4
<!--#embed nav_total --> 4 4 4 4
<!--#embed nav_next --> bob sally sue joe
<!--#embed nav_previous --> sue joe bob sally
<!--#embed nav_first --> joe joe joe joe
<!--#embed nav_last --> sue sue sue sue

This makes it very easy to build links and counters that automatically update when you add or rearrange pages in your page definitions file. Here's some example HTML that demonstrates this functionality:

<a href=../contemplate/assembler.php?page=<!--#embed nav_previous -->>Previous</a> |
<!--#embed nav_current --> of <!--#embed nav_total --> |
<a href=../contemplate/assembler.php?page=<!--#embed nav_next -->>Next</a>

Note that when processing navigation tags, Contemplate assumes that double line breaks in the page definitions file indicate a group of pages, and only considers the other pages in the same group as the current page.

Navigation tags don't require any arguments in your page definition. They do, however, require the use of a page definitions file rather than passing page definitions through the query string.

Conditional tags

<!--#if (left_column[2] != "home") -->, <!--#else -->, <!--#end if -->
If you want to use one template rather than two in cases where both templates are only slightly different, you could add logic to your template using client-side or server-side scripting to make it display differently in different circumstances. Or, you can use Contemplate's built-in conditional functionality to "show" or "hide" different portions of your template. The advantages of using Contemplate's conditional tags are that they're language-neutral and don't have to be rewritten if you move your site to a different platform, they run faster since Contemplate will completely eliminate the portions of the template you don't need when it assembles your page, and they allow easy access to portions of your page definition for making decisions based on those values.

Conditional tags can contain the same kind of references that you would include in a passthru tag, as in this example:

<!--#if (left_column[2] != "home") -->
<a href=home.html>Home</a>
<!--#else -->
Home
<!--#end if -->

They can also include any code that's compatible with the scripting language of the version of Contemplate you're using. For example, if you're using the PHP version of Contemplate, you could write a conditional tag that uses the strpos() function, as in this example:

<!--#if (strpos(left_column[1], "corporate/") !== false) -->
We're reading a content file from the content/corporate folder.
<!--#end if -->

However, including portions of the host scripting language means that you would have to rewrite those portions if you move your site to a different platform and change the version of Contemplate you're using.

As of version 1.0.3, conditional tags can even contain the names of the nav_* and env_* tags. For example, you could choose to display some content if the current page is the last in a group:

<!--#if (page[0] == nav_last) -->
Sorry, there are no more pages after this one!
<!--#end if -->

Or you could display some content if the page was modified today (this example uses the PHP strpos and date functions):

<!--#if (strpos(env_last_modified, date("Y-m-d") == 0) -->
Hey, this page is brand new!
<!--#end if -->

Environment tags

<!--#embed env_http_user_agent -->, <!--#embed env_remote_addr -->, etc.
Finally, you can display environment variables on your pages by including environment tags in your templates. The value of an environment tag is "env_" plus the name of the environment variable you wish to access, and is not case-sensitive. One additional environment variable is unique to Contemplate: <!--#embed env_last_modified --> will display the modification date of the newest of all the files used to build the page -- effectively, the modification date of the dynamic page.

Tag attributes

With standard, hard-coded, and passthru tags, you can also include a few different attributes to modify the display of the embedded content:

strip

<!--#embed main strip -->
If you include the strip attribute in your embed tag, Contemplate will strip all HTML tags from the embedded content before merging it into the template. This is a good way to clean up content if you need to override its formatting in your template, or embed it into a JavaScript variable.

replace

<!--#embed main replace /[\r\n]// -->
You can take even more control of the formatting of embedded content by running regular expression replacements on it. The example above removes all line breaks, which is also useful when embedding content into a script. You can include both the strip and replace attributes in a single embed tag, and you can list several replace attributes, each with its own regular expression values. Regular expressions are Perl-compatible and use the $n syntax for backreferences.

variable

<!--#embed main variable -->
If you want to embed content into a template but process the content using your own server-side scripts before displaying it, you can include the variable attribute in your embed tag. In this case, Contemplate finds your requested content, but rather than merging it into the template, creates a variable that you can access from scripts written in the same language as the version of Contemplate you're using. For example, if you're using the PHP version of Contemplate and you include the embed tag above, any PHP scripts in your template or content files can automatically access the embedded content through the $main variable. Note that it's then up to you to eventually print the content when you're finished working with it. Also note, if you use the variable attribute in a hard-coded tag, the content will be available in a variable called $hardcoded. If you use the variable attribute in more than one hard-coded tag, the content will be available in a series of variables called $hardcoded_1, $hardcoded_2 and so on.

fill_defer

<!--#embed main fill_defer -->
If you're using the Contemplate Formulator to edit page definitions, and you're embedding content into client-side or server-side scripts, the Formulator will try to place its content selection menus in the middle of your scripts, causing your pages to display incorrectly and trigger various browser errors. You can avoid this problem by adding the fill_defer attribute to any embed tags that you place inside of scripts. The Formulator will then place the content selection menus for these tags at the bottom of the page, rather than in the exact location as the tags themselves, allowing the page to display properly.

##content

Content files

After setting up your templates, creating content files is relatively easy. The most common type of content file is simply an HTML file that contains one large table:

##home This is the home page content. It can contain pictures, multimedia objects, and any kind of HTML formatting you can think of.
##contact_us This is the contact us page content. Ditto.
##site_map This is the site map page content. Ditto.
##home_sidebar This is content that we'll put in the sidebar of the home page. We've placed it in a separate field from the other home page content so that we can rearrange their positions on the page without editing this file.

The only rules for content files are that you lay out your fields in table cells as shown here, that each field name begin with the field marker, and that each field have a unique, alphanumeric name. Beyond that, you can name and organize your content fields and files in whatever way works best for you. The default field marker is "##," but you can use a different field marker by specifying any string in the contemplate/data/preferences.ini file.

If you prefer, you can delineate your content fields using XML tags rather than an HTML table:

<contemplate>

<group name="thoreau">

<content name="drummer">
If a man does not keep pace with his companions,
perhaps it is because he hears a different drummer.
</content>

<content name="dreams">
I learned this, at least, by my experiment: that if one advances
confidently in the direction of his dreams, and endeavors to live the
life which he has imagined, he will meet with a success unexpected in
common hours. </content>

</group>

</contemplate>

If you then give your content file and .xml extension, Contemplate will process it accordingly. The group tags are optional, but if you use them you can nest them to as many levels as you want to organize your content. In this case, your page definitions would refer to content using slashes between the levels, as in this example: quote=field,quotes.xml,thoreau/drummer.

Finally, you can save your content in .txt or other plain-text formats. However, you will only be able to embed the entire file into your templates, since Contemplate won't know how to find smaller pieces of content within the files.

##page_definitions

Page definitions

Once you've created content files and templates, you'll need a page definition to pull them together. You can use page definitions in two ways: either as the query string of a URL, or as the definition in a page definitions file. The latter is preferred since it results in cleaner URLs, provides a way to change the composition of a page globally, and allows you to use navigation tags and the Flattener if you need to.

To use the query string method, you would simply browse to a URL like this one:

http://www.yoursite.com/contemplate/assembler.php?template=default.html&main=field,main.html,home

To use a page definitions file, you would add this line to contemplate/data/pages.txt (or another file specified in your contemplate/data/preferences.ini file):

home: template=default.html&main=field,main.html,home

Then, you could browse to this simpler URL:

http://www.yoursite.com/contemplate/assembler.php?page=home

Each line of your page definitions file should consist of the page name, followed by a colon and then a space, followed by the template and other arguments needed to assemble your page. In addition, you can include comments and other text on their own lines to organize your page definitions file. And you can use extra line breaks to group your pages, which is especially useful in conjunction with navigation tags.

Content types

The first argument of each page definition should be the name of a template file, including the extension, and including the relative path to the file if it's not stored in the top-level templates folder. Additional arguments can have a different number of comma-delimited values, depending on the type of content they refer to:

file

main=file,home.html
The simplest way to embed content into a template is to embed an entire file. In this case, you can use a page argument with two elements: the keyword "file" and the name of the file, including the extension, and including the relative path to the file if it's not stored in the top-level content folder

field

main=field,main.html,home
The most common type of content is a field within an HTML or XML content file. To access one of these pieces of content, you can use a page argument with three elements: the keyword "field," the name of the content file, and the name of the field.

random

sidebar=random,tidbits.html
If you want to embed one field from an HTML or XML content file, but want to embed a different field each time the page loads, you can use a page argument with two elements: the keyword "random" and the name of the content file.

form

data=form,employee_data.html,joe,birth_date
If you want to access small pieces of content, such as an employee's birth date, it might be more convenient to create an HTML form inside of a content field, then set the names and values of the form elements. In this case, you can use a page argument with four elements: the keyword "form," the name of the content file, the name of the field, and the name of the form element. Contemplate will automatically find the values of text, textarea, radio, checkbox, and select elements. When checkbox or select elements contain multiple values, Contemplate displays a comma-delimited list of values.

menu

nav=menu,main.html,main,text
Imagine being able to rearrange, add to, or update a heirarchical, animated menu by simply pushing links around in an HTML editor. If you build content-driven menus in Flash, DHTML, or another technology, Contemplate can help you bridge the gap between data formatted for the menu software and data formatted for a human to update. You can set up your menu data in simple bulleted lists in your content file, like this:

Then you can place any of these embed tags into JavaScript code in your template:

<script language=JavaScript>
     menu_text = <!--#embed args=menu,main.html,menu,text -->;
     menu_links = <!--#embed args=menu,main.html,menu,links -->;
     menu_images = <!--#embed args=menu,main.html,menu,images -->;
     menu_images_width = <!--#embed args=menu,main.html,menu,images_width -->;
     menu_images_height = <!--#embed args=menu,main.html,menu,images_height -->;
     menu_images_alt = <!--#embed args=menu,main.html,menu,images_alt -->;
     menu_active = <!--#embed args=menu,main.html,menu,active -->;
</script>
<noscript>
     <!--#embed args=menu,main.html,menu,HTML -->
</noscript>

And Contemplate will convert the menu HTML to JavaScript arrays:

<script language=JavaScript>
     menu_text = ['Home', ['Products', 'Betaboard', 'Macroscope'], ['Contact', 'Remote', 'In person'], 'Site map'];
     menu_links = ['../contemplate/assembler.php?page=home', ['../contemplate/assembler.php?page=products', '../contemplate/assembler.php?page=products_betaboard', '../contemplate/assembler.php?page=products_macroscope'], ['../contemplate/assembler.php?page=contact', '../contemplate/assembler.php?page=contact_remote', '../contemplate/assembler.php?page=contact_in_person'], '../contemplate/assembler.php?page=site_map'];
     menu_images = ['', ['', '', ''], ['', '', ''], ''];
     menu_images_width = ['', ['', '', ''], ['', '', ''], ''];
     menu_images_height = ['', ['', '', ''], ['', '', ''], ''];
     menu_images_alt = ['', ['', '', ''], ['', '', ''], ''];
     menu_active = [0,1];
</script>
<noscript>
      <ul class="body">
            <li><a href="../contemplate/assembler.php?page=home">Home</a></li>
            <li><a href="../contemplate/assembler.php?page=products">Products</a>
                 <ul>
                        <li><a href="../contemplate/assembler.php?page=products_betaboard">Betaboard</a></li>
                        <li><a href="../contemplate/assembler.php?page=products_macroscope">Macroscope</a></li>
                  </ul>
            </li>
            <li><a href="../contemplate/assembler.php?page=contact">Contact</a>
                  <ul>
                        <li><a href="../contemplate/assembler.php?page=contact_remote">Remote</a></li>
                        <li><a href="../contemplate/assembler.php?page=contact_in_person">In person</a></li>
                  </ul>
            </li>
            <li><a href="../contemplate/assembler.php?page=site_map">Site map</a></li>
      </ul>
</noscript>

Menu arguments contain four elements: the keyword "menu," the name of the content file that contains your bulleted list, the name of the field that contains your bulleted list, and the type of data you wish to extract from the list: "text," "links," "images," "images_width," "images_height," or "images_alt" (the value of the HTML alt tag for each image). You can also use an embed tag with a fourth argument of "active" to embed an array indicating the position in the menu that corresponds to the current page. And we recommend using an embed tag with a fourth argument of "HTML" to place the menu HTML directly into a <noscript> tag, to allow search engines and other software to navigate your site.

Contemplate supports heirarchical menus with any number of levels. The only exception is that the active function in the Perl version of Contemplate only finds the menu position down to the second level.

search

main=search
Contemplate includes a built-in site search feature, which you can try in the left sidebar of this site. To use it on your site, you can set the embed type of any tag to "search," then include an argument "search_string" in your page's query string. Contemplate will search all of your content files and display a ranked list of results where the embed tag appears. For example, if a template called "default.html" contains an embed tag called "main" and you make a page definition "search_results: template=default.html&main=search," then the address "contemplate/assembler.php?page=search_results&search_string=guitar" will generate a listing of all the pages in your site containing the word "guitar."

passthru

colors=#000000,#FF0000,#999999
Sometimes you just need to pass data directly from the page definition to the template, and don't need a content file at all. In this case, you can include additional arguments in your page definition with as many elements as you need, and you can then access those elements in your template with tags like <!--#embed colors[0] -->, <!--#embed colors[1] -->, and so on.

URL rewriting

If you're using a page definitions file and the simpler URL format, you can make your URLs even cleaner by using your the URL rewriting functionality built into some web servers. For example, this site uses a RewriteRule in an Apache .htaccess file to convert URLs like assembled/home.html to contemplate/assembler.php?page=home. As a result, the site appears to the unsuspecting visitor to be a simple collection of static HTML pages; more importantly, it's completely compatible with search engines and other scripts that might ignore query strings in URLs.

Here's the rewrite rule this site uses:

RewriteRule ^assembled/(.+).html$ /software/contemplate/contemplate/assembler.php?page=$1&%{QUERY_STRING}

Note that this rule passes any additional query variables through to the real URL. This allows you to build web applications that pass data unrelated to Contemplate into your pages, or even to override your Contemplate page definition on a per-request basis.

Other arguments

If you're using Contemplate to build a web application, you can include other arguments in your query strings regardless of which method you use. For example, you might use any of these URL formats...

http://www.yoursite.com/contemplate/assembler.php?template=default.html&main=field,main.html,home&userID=1
http://www.yoursite.com/contemplate/assembler.php?page=home&userID=1
http://www.yoursite.com/assembled/home.html?userID=1

...but in each case, the userID argument will be available to any scripts contained in the assembled page.

##preferences

Preferences

The Contemplate folder contains a preferences.ini file that lets you change some of its behavior on a site-wide basis. To set a preference, just list the name of the preference on a line, followed by a colon and then a space, followed by the value you wish to set the preference to. If you don't include a preference name in your preferences.ini file, Contemplate will use the default value, which you can look up in the list below. For an example, you can view the preferences.ini file for this site.

NOTE: Before version 1.0.4, the default location for this file was the contemplate directory. If you've upgraded to version 1.0.4 or newer and Contemplate isn't reading your preference settings, move your preferences file from contemplate to contemplate/data.

Setting preferences on the fly

When you view a Contemplate page in your browser, you can change most of these preferences for the current view only by passing the preference name (with spaces changed to underscores) and value into the Contemplate script through the query string. For example, if the show errors preference is set to 0 in your preferences.ini file, but you want to temporarily see the errors on a particular page, you can add &show_errors=1 to the URL you're viewing. Contemplate won't let you set a few preferences in this way for security purposes; those preferences are noted in the list below.

Assembler preferences

field marker

Default: ##
Possible: any string
The field marker is a special string that helps Contemplate locate the names of content fields. You should use a string that won't appear anywhere in your site content. The default field marker will usually work, but if you need to use a different string, you can set it here.

log site traffic

Default: 0
Possible: 1 or 0
If you set this preference to 1, Contemplate will log every page request to a data file that you can view through the Reporter component. You'll also need to set the contemplate/data/reporter folder to be world writable, otherwise Contemplate will write a comment at the bottom of each page noting that the data file is unavailable.

host lookups for logs

Default: auto
Possible: on, off, auto
When Contemplate logs site traffic, it can log the hostname of the visitor even if hostname lookups are turned off at the server level by performing its own hostname lookup. If you set this to on, Contemplate will always perform a lookup and therefore always log a hostname. If you set this to off, Contemplate will never perform a lookup and therefore only log a hostname if lookups are turned on at the server level. If you set this to auto, Contemplate will perform a lookup only if lookups are turned off at the server level and therefore always log a hostname. The auto setting is preferable because it provides the most useful logs reports without duplicating the hostname lookups.

show errors

Default: 1
Possible: 1 or 0
When Contemplate assembles pages, it will display errors if it encounters an invalid page definition or it can't find the files or fields you specify. If you set this to 1, it will display these errors on the assembled page so the visitor can see them. If you set this to 0, it will surround these errors in HTML comment tags so the visitor has to view the page source to see them. If the log site traffic preferences is set to 1, Contemplate will log these errors in the data file regardless of this setting.

pre-render files

Default: nothing
Possible: any file extensions
Example: cgi
Normally, Contemplate reads all content files and templates through the filesystem, then assembles the final page. However, if your content files or templates contain server-side scripting, you might want those scripts to execute before Contemplate begins the assembly. If you list file extensions here, with no periods, delimited by commas, Contemplate will read any files with those extensions through the web server rather than through the filesystem, so the scripts will execute first. Then Contemplate will perform its assembly based on the output of those scripts.

read page definitions from

Default: data/pages.txt
Possible: any path
By default, Contemplate looks for page definitions in this file, but you can move or rename your page definitions file if you update this preference. The default path for this setting is the contemplate/data directory, but you can store your definitions file elsewhere if you use a setting like ../other/pages.txt.

NOTE: Before version 1.0.4, the default location for this file was the contemplate directory. If you've upgraded to version 1.0.4 or newer and Contemplate can't find your page definitions, change this value from pages.txt to data/pages.txt.

read files from

Default: nothing
Possible: any paths
Example: ../scripts/, ../other/
No override
As a security precaution, Contemplate can only read files in the top-level content and templates folders as well as its own folder. However, you might want to organize your site differently and store your files in different folders. If you list folder paths here, relative to the contemplate folder, with a trailing slash, delimited by commas, Contemplate will be able to read any files in those folders as well.

read files recursively

Default: 1
Possible: 1 or 0
No override
By default, Contemplate will automatically read files in all the subfolders of the content and templates folders and the additional folders you specify in the read files from setting. However, sometimes you may want to ignore subfolders, especially to speed up page display or avoid problems with irrelevant file types in the Formulator. If so, you can include this setting in your preferences file and set it to 0. You can still direct Contemplate to read from specific subfolders by adding those subfolders to your read files from setting.

require authentication to read files from

Default: nothing
Possible: any paths
Example: ../staff/, ../clients/
No override
Adding a password-protected area to your site can be difficult since Contemplate pages are comprised of elements from several different folders. You can't simply password-protect the Assembler file because that would require a login for all your pages; and you can't password-protect individual content folders, because the Assembler reads content through the filesystem, bypassing any password protection. This option lets Contemplate work in conjunction with the HTTP Basic Authentication mechanism on your web server. If you list folder paths here, the Assembler will check to see if users have authenticated before loading content files or templates that are stored in those paths. The Assembler won't actually check to see that the username or password is correct; it relies on the web server to do that, and assumes that if a username is present among the server's environment variables, the user authenticated correctly. If a username is not present when a user tries to view an affected page, the Assembler will display an error message. NOTE: This option has not been tested in the ASP version and is not included in the Perl version.

prevent page caching

Default: 0
Possible: 1 or 0
If you set this preference to 1, Contemplate will add Pragma, Cache-control, and Expires headers to every page it assembles, which will prevent most web browsers from caching those pages.

show expanded URLs

Default: 0
Possible: 1 or 0
If you browse to a Contemplate page using a URL of the format assembler.php?page=page_name, and this preference is set to 1, Contemplate will reload the page with the full URL as shown in the page definitions file. This can be useful for troubleshooting but is not recommended as a permanent setting for your site since it causes every page to load twice.

split page names on

Default: nothing
Possible: any character or string
If you set a value for this preference and then use the special page variable in your embed tags, Contemplate will split the page name on this value and let you access elements of the resultant array by providing an index to the page variable (e.g., page[1]). You can still access the entire page name by leaving out the index to the page variable (e.g., page[]).

external link target

Default: nothing
Possible: any string
Example: "_blank"
You can ensure that every link on your website that connects to a separate site opens in a new window by setting an external link target. When Contemplate assembles a page, it will include a target attribute, with the value set here, in every anchor tag whose href contains an absolute URL to an http page. This setting does not affect https or ftp URLs. If you want Contemplate to put quotes around the value, include the quotes in your preference setting.

line ending for assembled files

Default: \n
Possible: any string
You can control the line endings that Contemplate uses when assembling files by setting this preference. For example, if you're flattening a site and want to easily read the source of the flattened files on a Windows computer, you can set this preference to \r\n.

show source

Default: 0
Possible: 1 or 0
If you're adding server-side scripting to your templates or content files and those scripts generate errors, the line numbers in your error messages may be inaccurate because they refer to the line number of the error in the context of the assembled page rather than in the context of the actual script file you're editing. To help locate errors from one context to the other, you can set this preference to 1 (including setting its value on the fly by passing it through the URL string). In that case, Contemplate will display the assembled page, and at the bottom will also display the complete source code of the assembled page (including your scripts before they execute), along with line numbers for the assembled page. Those line numbers should correspond to the line numbers specified in your error messages, which will help you locate the problematic line of code.

show source to IP address

Default: nothing
Possible: any addresses
Example: 216.08.59.13, 10.0.1.12
No override
In order to keep your source code private, Contemplate will only respect the show source setting for requests that come from IP addresses that you specify. You can list IP addresses here, delimited by commas, to enable the show source preference for requests coming from those addresses. Contemplate currently doesn't support any wild card matching of partial addresses or subnets; it only recognizes single, complete addresses.

Reporter preferences

top n

Default: 5
Possible: any integer
By default, the Reporter shows initial lists of the top 5 items in each category, but you can change this value to show any number of items in the initial lists. In any case, Reporter always provides a link to see the complete lists.

graph image

Default: ../graphics/logo.jpg
Possible: any string
If you're using the real-time traffic view at reporter/realtime.swf, you can specify any image file on your website to display behind the timeline. Contemplate will fade the logo into the background of the window so your traffic timeline is still legible. The only supported image format is non-progressive JPEG, and the path to the image is relative to the contemplate directory.

graph color

Default: 0000FF
Possible: any string
If you're specifying your own logo for display behind the real-time traffic view, you can also use this setting to make text links and buttons color-coordinate with your logo. Just enter any RGB hex value here.

real-time update interval

Default: 10
Possible: any integer
If you're using the real-time display feature, you can change the frequency with which the Flash file reads the current traffic data file to count new page views. This value specifies the number of seconds between updates.

maximum column width

Default: 64
Possible: any integer
When the Reporter displays referrer data and other long values, it will crop those values to a reasonable length so that the traffic reports still display well in your browser window. However, depending on your preferred window size, you can adjust this number to make the Reporter crop the values to longer or shorter sizes, optimizing your display.

display monthly report on one big page

Default: 0
Possible: 0, 1
By default, the Reporter displays the top n lists on one page, and provides links to view the complete lists on separate pages. However, if you enable this value, the Reporter will display the top n lists as well as the complete lists for each category on one page. It presents the same links, but in this case they simply jump to different portions of the page. This option results in a much slower initial page load, but faster navigation between sections once the page is loaded.

show inspector rollover

Default: 1
Possible: 0, 1
Each entry in your traffic reports includes a small magnifying glass icon that you can use to open an "inspector" view, providing a different cross-section of your traffic reports. By default, this icon uses a standard HTML rollover effect. However, the additional code required for the rollover effect may cause a noticeable increase in page load time with longer reports, and you can optionally skip the rollover effect and speed up the page loading by disabling this option.

exclude traffic from hosts

Default: googlebot, msnbot
Possible: any hostname or portion of a hostname
You can exclude selected site traffic from your traffic reports with this option. For example, you might wish to exclude traffic from your own company to get a more accurate picture of your site's public users. You might also wish to exclude traffic from automated search engine "bots." To exclude traffic from these hosts, set this value to a comma-delimited list of strings that identify the hosts you wish to exclude. The Reporter still logs traffic from these hosts, it just doesn't include them in the report. This means you can change your preference setting at any time without losing any traffic data.

use cookies to track visitors

Default: 0
Possible: 0, 1
Normally, the Reporter tracks individual page views but does not try to link consecutive page views together into a "visit." With this option enabled, the Assembler will assign each website visitor a randomly-generated visitor ID and save it in a cookie on the visitor's computer. It will then include the visitor ID in each page view record so the Reporter can link them together. When the option is enabled, the Reporter's month menu page will display the number of visitors in the month, the number of visits and average visits per visitor, and the average visit duration, and the monthly report pages will display the visitor IDs and the entry and exit pages.

minutes until visit expires

Default: 30
Possible: any integer
With the "use cookies to track visitors" option enabled, the Reporter will consider a group of page views by the same visitor with no more than 30 minutes between any consecutive page views as a "visit." To change the 30-minute limit to a different value, you can use this option. Contemplate determines visits when you view a report, not when it logs the page view, so you can change this value at any time and view the effects on your reports retroactively.

##tips

Tips and tricks

Changing file permissions

Some of the Contemplate components write to files on your web server, so to use these features, you'll have to change the permissions on some of your files and directories. To use the Reporter component, make the contemplate/data/reporter directory world-writable. To use the Formulator, make the contemplate/data/pages.txt and contemplate/data/pages.txt.backup files world-writeable. To use the Flattener, make the flattened directory world-writeable.

Accessing content without a template

If you want to quickly display a piece of content in your content files without merging it into a template, or if you want to access individual pieces of content for display by a dynamic Flash file or other system, you can pass an args value to the Assembler script:

../contemplate/assembler.php?args=field,misc.html,alert_message

You can construct this args value just as you would construct a hard-coded embed tag in a template.

Using server-side scripts

If you include server-side scripts in your content files or templates, they will execute after the page is assembled if they're written in the same language as the version of Contemplate you're using. For example, if you're using the PHP version of Contemplate and you include the script <?php $name="Joe"; ?> in a content file and the script <?php print $name; ?> in your template, your assembled page will include the text "Joe." You may use scripts written in either VBScript or JScript with the ASP version of Contemplate, using either the <% %> (for VBScript only) or <script language="language" runat="Server"></script> tags. With all versions of Contemplate, scripts written in other languages may or may not execute, depending on the capabilities and configuration of your web server.

##components

Other components

The heart of Contemplate is the Assembler script, which merges content into templates to create finished HTML pages. However, the Contemplate package includes a few supporting utilities that are worth getting to know. You can access these by browsing to the contemplate directory of your website, where you should see this page:


(Click to enlarge)

We recommend limiting access to these utilities by password-protecting each component's directory after adding the Contemplate scripts to your website. The default Contemplate installation includes generic htaccess and htpasswd files to get this started on Apache systems.

You can disable any of these components for your site by opening the contemplate/data/index_settings.js file and removing values from the components_enabled variable.

Formulator

For many site editors, the process of defining and modifying page definitions can be daunting. The Formulator is a visual editor for the page definitions file that site editors can use rather than working in the file directly. The Formulator offers four options -- build a new page from scratch, build a new page based on an existing page, edit an existing page, or delete an existing page -- then leads editors through the process of selecting which pieces of content to display in the place of each embed tag in the template. At the end of the process, the Formulator shows which URLs the editor can use to browse to the new page. Note that the Formulator doesn't have the capability to edit content, merely to place content into templates to create page definitions.


(Click to enlarge)

Flattener

If you want to build a site using Contemplate but need to deliver it in an environment where server-side scripting is not available (such as on a very basic web server or on a CD-ROM), you can develop your site, then "flatten" it. The Flattener component reads your page definitions file and creates a static HTML file for each page listed there. In the process, it edits all the links in your site to point to the flattened versions of your pages, so the only link you'll need to change is the link from your home page to your first Contemplate page.

The first option on the Flattener page flattens your entire site, placing the static HTML files into a top-level folder called flattened. If you've already flattened your site and need to re-flatten just a subset of pages, you can save time by only flattening files whose names match or don't match a given string. If you want to see how your flattened pages will look before actually flattening them, you can use the Preview option to display all pages in their flattened form in a single window. The Preview option also makes a nice troubleshooting tool, since it can give you a quick look at every page of your site.

The second option lets you choose a particular input file and output name and flatten that file only; this is useful for making a version of your home page that links to the flattened versions of your Contemplate pages.


(Click to enlarge)

Reporter

Most web hosts provide some kind of statistics package for their websites, but many are difficult for the average person to read, and some may not distinguish between requests like assembler.php?page=one_page and assembler.php?page=another_page. Contemplate addresses both of these problems with its built-in statistics component called the Reporter. If you turn on the log site traffic preference in your preferences.ini file, Contemplate will keep log files of your site traffic that you can read with the Reporter. This provides a simple, clear view of your site traffic, including readable page names (one_page and another_page) and errors encountered by Contemplate while assembling pages for your visitors.


(Click to enlarge)

##release_notes

Release notes

If you need to know exactly how Contemplate has changed from one version to the next, or would like more insight into the development and functionality of these scripts, please review the release notes for each component:

Assembler

Formulator

Flattener

Reporter

 
##issues

Known issues

This list includes aspects of Contemplate that we want to change, but that we're currently stuck on. If you have ideas about how to address these issues, !

  • When using the replace attribute in an embed tag to do regular expression replacements, you can't use the character / (forward slash) in either your search or your replace string.
  • Currently, the PHP and ASP versions of Contemplate will pass authentication information through the assembly process so that you can flatten a password-protected site. However, this feature is not included in the Perl version.
  • In some cases, conflicts will occur if you give an embed tag the same name as one of Contemplate's internal variables. We're currently looking into an elegant way to prevent this problem in all cases.

Next steps

This list includes our plans for the next major release, Contemplate 2.0. if you have any comments about these plans.

  • Use an HTML parsing module instead of regular expressions in the Assembler. Contemplate relies heavily on regular expressions (having originated as a Perl script), but these tend to be buggy and could be faster. We're exploring better ways to parse HTML content files.
  • Support storage of content in a database. Contemplate was originally designed around the idea of using your favorite desktop HTML editor on standard HTML content files. But with the ongoing improvement of web-based editing components like TinyMCE, and the availability of fully-functional editors like Meditate, not to mention the ubiquity of database support on web servers, this has become a more useful option. With this approach, web developers would use the same tag syntax to retrieve content from database tables instead of HTML files.
  • Store Reporter data in a database. The Reporter shows great info in a streamlined interface, but it bogs down when sites start generating a lot of traffic. Storing traffic data in a database rather than flat files should make this component much more robust.
  • Simplify the Formulator. This component still has potential, but is difficult to use and maintain. A slightly more streamlined approach might hold up to real-world use better.
  • Drop support for the Flattener. Running websites from a CD-ROM or hard drive is no longer common as it was in 1999 when Contemplate was first developed. Instead of maintaining the Flattener, optimizing the Assembler code for performance would be more useful.

Wish list

This list includes ideas that we're considering adding to Contemplate in the future, but we're either not sure how we want to implement them, or we just haven't gotten to them yet.

  • It would be great if, rather than showing the current, very boring error message when it can't find a page definition, Contemplate returned a status=404 header so that the web server displayed its normal File Not Found page. The Assembler scripts already contain a line of code to do this, but none of them seem to have any effect.
  • It would be nice if the functions that we've duplicated across various Contemplate scripts were saved in a single, shared file. However, we're not sure how to do this in the Perl version, and we might prefer to keep things as they are now to save one more file load during the assembly process.
  • We should be able to rewrite some of the regular expression matching to use global matches rather than while loops, which should speed up parsing considerably.
  • Currently, XML content files must follow the very simple document type definition shown in the demo site. However, we've not yet created a DTD file that documents this structure. More significantly, we haven't considered what it would take to make Contemplate support XML content files based on other DTDs.
  • We think it would be cool to use multiple page definitions files in a site. However, we would then need to include the name of a page definitions file with every page request, like assembler.php?definitions=pages2.txt&page=foobar, and that might not be worth the extra clutter.
  • It might be nice to format page definitions files as XML, but we're not sure. They can be a little hard to read either way.