Use templating with Sitemagic CMS

Sitemagic CMS features a simple yet powerful templating engine that enables true separation between layout (presentation) and logic. This greatly simplifies the process of building design templates for Sitemagic CMS, but also provides great flexibility for defining the layout of extensions. Imagine an extension such as a webshop that needs to be flexible enough to let designers decide how to present products. This can be easily achieved using templates.

Working with place holders
First of all let's examine a simple template using place holders to define where to insert data. Our extension is used to present information about a company.
CompanyProfile.html
<img src="{[CompanyImageUrl]}" alt="{[CompanyName]}" style="float: left; margin-right: 20px">
<h1>{[CompanyName]}</h1><br>
<i>{[CompanyDescription]}</i><br><br>
{[CompanyPhone]}<br>
<a href="mailto:{[CompanyEmail]}">{[CompanyEmail]}</a>
<div style="clear: both"></div>
The HTML code above will result in the company being presented with an image to the left, and associated company information such as company name, company description, phone number, and e-mail address to the right. We use place holders to define where data is to be inserted by our extension. Below we'll examine what it takes to replace these place holders with actual data. We assume CompanyProfile.html is stored in the root of our extension folder.
$templateFile = SMExtensionManager::GetExtensionPath($this->context->GetExtensionName());
$templateFile = $templateFile . "/CompanyProfile.html";

$template = new SMTemplate($templateFile);
$template->ReplacePlaceholder(new SMKeyValue("CompanyName", "Sitemagic CMS"));
$template->ReplacePlaceholder(new SMKeyValue("CompanyDescription", "We do web designs"));
$template->ReplacePlaceholder(new SMKeyValue("CompanyPhone", "555-8251"));
$template->ReplacePlaceholder(new SMKeyValue("CompanyEmail", "contact@domain.com"));

$output = $template->GetContent();
The example above will load our template, replace the place holders within, and return the modified content to the $output variable which can now be returned to Sitemagic CMS for presentation.

Working with repeating blocks
Quite often we need to be able to present a variable amount of data, for instance from a database. For that to work we need to be able to define a block that represents the presentation of a single item, and have the system repeat that block for each item found. We use repeating blocks for that:
CompanyList.html
<table cellspacing="0" cellpadding="0" border="1">
    <tr>
        <td><b>Company</b></td>
        <td><b>Description</b></td>
        <td><b>Phone</b></td>
        <td><b>E-mail</b></td>
    </tr>
    <!-- REPEAT CompanyList -->
    <tr>
        <td>{[CompanyName]}</td>
        <td>{[CompanyDescription]}</td>
        <td>{[CompanyPhone]}</td>
        <td>{[CompanyEmail]}</td>
    </tr>
    <!-- /REPEAT CompanyList -->
</table>
In this example we have defined a template that presents company information in a table structure. Inserting data into this template is also quite easy as the code below demonstrates.
// Prepare some test data

$company1 = new SMKeyValueCollection();
$company1["CompanyName"] = "Sitemagic CMS";
$company1["CompanyDescription"] = "We make Content Management easy";
$company1["CompanyPhone"] = "555-8251";
$company1["CompanyEmail"] = "contact@domain.com";

$company2 = new SMKeyValueCollection();
$company2["CompanyName"] = "Codemagic inc.";
$company2["CompanyDescription"] = "Creating great software is our passion";
$company2["CompanyPhone"] = "555-7299";
$company2["CompanyEmail"] = "sales@domain.com";

$companies = array($company1, company2);

// Insert company information into template

$templateFile = SMExtensionManager::GetExtensionPath($this->context->GetExtensionName());
$templateFile = $templateFile . "/CompanyList.html";

$template = new SMTemplate($templateFile);
$template->ReplaceRepeatingBlock("CompanyList", $companies);
Usually data comes from a database or data source as we call it in Sitemagic CMS. This could look something like this:
// Load company data from data source

$ds = new SMDataSource("Companies");
$companies = $ds->Select("CompanyName, CompanyDescription, CompanyPhone, CompanyEmail");

// Insert company information into template

$templateFile = SMExtensionManager::GetExtensionPath($this->context->GetExtensionName());
$templateFile = $templateFile . "/CompanyList.html";

$template = new SMTemplate($templateFile);
$template->ReplaceRepeatingBlock("CompanyList", $companies);
Notice how the returned data from a data source seamlessly "plugs in" to the templating system with no transformations necessary. With just a few lines of code we can map data from a data source to the presentation layer in a very intuitive way. Simply make sure to have fields in the data source named identical to place holders in the template.
Working with nested repeating blocks
In some cases nesting repeating blocks make sense (repeating blocks in repeating blocks). This is used in e.g. design templates to define navigation menus with multiple levels. Let's see how this approach can be used to created a nested list as shown below:
NestedList.html
<ul>
    <!-- REPEAT Categories -->
    <li>{[Category]}</li>
    <ul>
        <!-- REPEAT Links {[Id]} -->
        <li><a href="{[Url]}">{[Title]}</a></li>
        <!-- /REPEAT Links {[Id]} -->
    </ul>
    <!-- /REPEAT Categories -->
</ul>
 
What we want to achieve

The code below inserts data for the NestedList.html template above.
// Step 1 - Access template file

$templateFile = SMExtensionManager::GetExtensionPath($this->context->GetExtensionName());
$templateFile = $templateFile . "/NestedList.html";
$template = new SMTemplate($templateFile);

// Step 2 - Load and insert categories into template

$dsCategories = new SMDataSource("Categories");
$categories = $dsCategories->Select("Category, Id");

$template->ReplaceRepeatingBlock("Categories", $categories);

// Step 3 - Load and insert links under each category

$dsLinks = new SMDataSource("Links");
$links = null;

foreach ($categories as $cat)
{
    $links = $dsLinks->Select("Title, Url", "CategoryId = '" . $cat["Id"] . "'");
    $template->ReplaceRepeatingBlock("Links " . $cat["Id"], $links);
}

// Step 4 - get content from template

$content = $template->GetContent();
In step 1 we load our template file, allowing us to replace repeating blocks and contained place holders.
In step 2 we load category information and replace the Categories repeating block, as well as the Category place holder and Id place holder. After this step the content of the template looks like this:
Content of template after step 2
<ul>
    <li>Computers</li>
    <ul>
        <!-- REPEAT Links 1 -->
        <li><a href="{[Url]}">{[Title]}</a></li>
        <!-- /REPEAT Links 1 -->
    </ul>
    <li>Operating systems</li>
    <ul>
        <!-- REPEAT Links 2 -->
        <li><a href="{[Url]}">{[Title]}</a></li>
        <!-- /REPEAT Links 2 -->
    </ul>
</ul>
Notice how the Links repeating block got repeated (or copied) during step 2. This produced two new repeating blocks based on the category ID (Links 1 and Links 2) which are now ready to be populated.
In step 3 we load links associated with a given category, and insert them into the relevant Links X repeating block (X being the category ID).
Finally we fetch the content in step 4 which now contains all our information as shown below.
 Content of template after step 3
<ul>
    <li>Computers</li>
    <ul>
        <li><a href="http://www.dell.com/">Dell</a></li>
        <li><a href="http://www.compaq.com/country/index.html">Compaq</a></li>
        <li><a href="http://www.apple.com/mac/">Mac</a></li>
    </ul>
    <li>Operating systems</li>
    <ul>
        <li><a href="http://www.ubuntu.com/">Ubuntu</a></li>
        <li><a href="http://windows.microsoft.com/en-us/windows/home">Windows</a></li>
        <li><a href="http://www.apple.com/osx/">Mac OSX</a></li>
    </ul>
</ul>