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. If you're ready to jump right in, here's an overview. Descriptions of the main parts of a Contemplate website. Guidelines for setting up the main folders of your website. A complete list of options for embedding content into templates. The anatomy of a Contemplate content file. An explanation of how you can pull it all together. Useful things you can change with the config/constants.php file. How to prohibit unwanted access to your content. The included Reporter script displays your site traffic. Miscellaneous goodies that don't fit elsewhere. Complete change histories for each Contemplate component. 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.
|
|||||||||||||||||||||||||||||||||||
##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. 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. And once you start using page definitions, it's easy to change the composition of your URLs with your server's URL rewriting features. |
|||||||||||||||||||||||||||||||||||
##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:
But if you decide to keep your content files in a folder called HTML, the page definition would look like this:
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 the constants.php file in the contemplate/config 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:
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 --> Hard-coded tags <!--#embed args=file,header.html --> Passthru tags <!--#embed highlight[0] --> 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
--> 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.
...and you place navigation tags into your template, they would display as follows on various pages:
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:
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 --> Conditional tags can contain the same kind of references that you would include in a passthru tag, as in this example:
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:
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:
Or you could display some content if the page was modified today (this example uses the PHP strpos and date functions):
Environment tags <!--#embed env_http_user_agent -->, <!--#embed
env_remote_addr -->, etc. 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 --> replace <!--#embed main replace /[\r\n]// --> variable <!--#embed main variable --> show_errors, hide_errors <!--#embed main show_errors -->, <!--#embed main
hide_errors -->
|
|||||||||||||||||||||||||||||||||||
##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:
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 "# If you prefer, you can delineate your content fields using XML tags rather than an HTML table:
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:
To use a page definitions file, you would add this line to config/pages.txt (or another file specified in your config/constants.php file):
Then, you could browse to this simpler URL:
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 field main=field,main.html,home database main=database,table,column,key_column, key_value
…is the equivalent of this SQL query :
If you leave out the last two elements, Contemplate will randomly select a field each time the page loads. In order to use this tag, you need to specify your database connection details in the constants.php file. form data=form,employee_data.html,joe,birth_date search main=search passthru colors=#000000,#FF0000,#999999 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 pages/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:
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...
...but in each case, the user argument will be available to any scripts contained in the assembled page. |
|||||||||||||||||||||||||||||||||||
##preferences | Preferences The config folder contains a constants.php file that lets you change some of its behavior on a site-wide basis. NOTE: Before version 2.0, preferences were stored in a text file located at data/preferences.ini. If you've upgraded to version 2.0 or newer, you will need to copy your preferences into the new config/constants.php file. Setting preferences on the fly When you view a Contemplate page in your browser, you can a few of these preferences for the current view only by passing the preference name (changed to lower case) and value into the Contemplate script through the query string. For example, if the SHOW_ERRORS preference is set to 0 in your constants.php 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. Only a few preferences can be set in this way because the others either aren't likely to be used, and would create extra processing overhead, or would create security issues. Those that can are noted in the list below. Assembler preferences field marker Default: # read page definitions from Default: config/pages.txt NOTE: Before version 2.0, the default location for this file was the contemplate/data directory. If you've upgraded to version 2.0 or newer and Contemplate can't find your page definitions, change this value from data/pages.txt to config/pages.txt. read files from Default: ../contemplate/config/,../content/,../templates/ read files recursively Default: 1 require authentication to read files from Default: nothing NOTE: As of Contemplate version 2.0, this option is known to be broken. Please contact us if you would like to use this functionality and we will prioritize fixing it. split page names on Default: nothing pre-render files Default: nothing search results preview length Default: 128 prevent page caching Default: 0 external link target Default: nothing line ending for assembled files Default: \n log site traffic Default: 0 use cookies to track visitors Default: 0 host lookups for logs Default: auto show expanded URLs Default: 0 show source Default: 0 show source to IP address Default: nothing show errors Default: 1 error box style Default: border: 2px solid black; padding: 8px; color: #000000;
background: #FFFFFF; error page 404 Default: nothing content database address Default: nothing content database tables Default: nothing content database strip slashes Default: false Reporter preferences password Default: nothing one big page Default: false top n Default: 5 maximum label length Default: 64 graph color Default: #0000FF graph image Default: nothing real-time update interval Default: 10 exclude traffic from hosts Default: bot,crawl,spider include error pages in totals Default: true minutes until visit expires Default: 30 reporter database address Default: nothing
|
|||||||||||||||||||||||||||||||||||
##security | Security The purpose of Contemplate is to display content from your web server, but there are some files and data that you will want to keep private. This page explains how Contemplate controls access to your content. Limit file access The config/constants.php file contains a READ_FILES_FROM setting that is a comma-delimited list of directories in your website. Contemplate will only read files from these directories. By default, the value is set to "../contemplate/config/,../content/,../templates/". This allows Contemplate to read its own config files (constants.php and pages.txt), plus the content and template files you create. You can list additional directories here if you want to keep your functionality scripts in a separate directory, or organize your files differently. Please do not put any files into these directories that you do not wish the public to see! A related setting is READ_FILES_RECURSIVELY, and this setting is enabled by default. If you disable this setting, Contemplate will not be able to read files from subdirectories of the READ_FILES_FROM directories. Limit database access If you store any of your content in a database, the CONTENT_DATABASE_TABLES setting works similarly to the READ_FILES_FROM setting. You can list your content tables here, and Contemplate will only read from those tables. This allows you to safely store your content into one or more tables of your database, without inadvertently exposing the rest of the database. Limit config access By default, a site visitor who knows the Contemplate file structure can browse to contemplate/config/pages.txt to view your page definitions. This would reveal pages you've built but aren't ready to release yet, and if you link to functionality scripts in separate files, it would reveal the locations of those files. So, it's a good idea to block access to the pages.txt file. The Contemplate download includes a sample htaccess file with an Apache <Files> directive to block access. If you move the htaccess file to your website root directory (and add a dot to the beginning of its filename), or copy this directive into an existing .htaccess file, the pages.txt file will be hidden from public view. The config/constants.php file does not need this kind of protection, because if a visitor browses to it, it will execute on the server rather than displaying its contents. Reporter password By default, a site visitor who knows the Contemplate file structure can browse to contemplate/reporter/reporter.php to view your traffic reports. You can password-protect your reports by entering a password for the PASSWORD setting in config/constants.php. Once this is set, the Reporter will prompt users to enter the password before displaying the reports. |
|||||||||||||||||||||||||||||||||||
##tips | Tips and tricks Using server-side code If you include PHP code in your templates or content files, it will execute after the page is assembled but before the page is sent to the browser. For example, if you include the code <?php $name="Joe"; ?> at the top of your template and the code <?php print $name; ?> in your embedded content, your assembled page will include the text "Joe." Scripts written in other languages may or may not execute, depending on the capabilities and configuration of your web server. Merging variable values into your content If you commonly display the values of PHP variables in your content, you can make your content easier to edit by placing variables like $name instead of <?php print $name; ?> and then converting those variables to their values before displaying the content. As of version 2.0, Contemplate includes a function called merge_values($content, $values) that you can use in your scripts, in conjunction with the variable embed attribute. This function finds any PHP variables in $content, and sets them to the corresponding values in $values, which is an associative array. For example, if you put the tag <!--#embed main variable --> into your template, and the content displayed there contains the $current_rank variable, you can calculate a value for $current_rank in your script and then call $main = merge_values($main, array("current_rank"=>$current_rank)) to merge the value into your content. This gives the same result as including <?=$current_rank?> into your content, but the content will be easier to edit by non-programmers. If you have several values to merge into your content, you can simplify the syntax of the merge_values command by first compacting them into one array:
Alternatively, you can simply pass all current values into the merge_values command:
Splitting your content to hide it or loop over it As of version 2.0, Contemplate also supports a new kind of tag that you can place into your content. A "split" tag extracts a portion of your content, puts it into a variable that your code can access and manipulate, and replaces the content with a reference to the variable. For example, if your embedded content contains the tags <!--#split warning_message --> and <!--#end split -->, then Contemplate will set a variable $split_warning_message containing the content between the split tags. Your script can then alter that variable, or set it to an empty string, to change or hide that content. When you are finished manipulating the $split_warning_message content, you can merge it back into your main content with $main = merge_values($main, array("split_warning_message"=>$split_warning_message)). A combination of the merge_values function and the split tags makes it easy to loop through a repeatable piece of content and merge data into it. For example, if you access a table row in your content via a $split_users variable, you can then iterate over a $users array, merging the $users data into each iteration of the row:
Remember that after manipulating any content that you capture with the variable attribute, you are responsible for displaying it with the echo or print functions. 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:
You can construct this args value just as you would construct a hard-coded embed tag in a template. Managing page definitions For web developers, editing the pages.txt file directly is usually the fastest way to add or reconfigure your pages. But for some users this can be inconvenient. As an alternative, you can install the Meditate(tm) Web Content Editor, and then use its page management feature to edit, copy, rename and delete your page definitions from a web interface.
|
|||||||||||||||||||||||||||||||||||
##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. 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 web pages and all the supporting files connected to each page. Contemplate addresses both of these problems with its built-in statistics component called the Reporter. If you set LOG_SITE_TRAFFIC to true in your config/constants.php file, Contemplate will log each page it assembles to a database, whose data you can view with the contemplate/reporter/reporter.php script. This provides a simple, clear view of your site traffic, using your own page names. |
|||||||||||||||||||||||||||||||||||
##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 the tool, please review the release notes: Before version 2.0, we maintained separate release notes for the Reporter and the now-defunct Formulator and Flattener. Those release notes are still available from the following links. However, only the Reporter release notes have any relevance to the current version of Contemplate, because the Formulator and Flattener have been completely removed. If you're working with older versions of Contemplate, you can also browse the documentation as it stood at version 1.3.1. |
|||||||||||||||||||||||||||||||||||
##issues | Known issues None at this time. 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.
|