NewsFeaturesDownloadsDevelopmentSupportAbout Us

Template Development

From LifeType Wiki

Contents

Introduction

Lifetype uses a template system in order to clearly separate what is content from what is the core code. The greatest advantage from the users point of view is, we ensure that from within the templates, the template developer will only have access to the things the code developer wants him to. That is, if from within the main page we only need to have access to the list of most recent posts, that will be the only thing we will "export" to the template. There is no risk that the user will (most of the times, unwittingly) mess up anything else because we give the user only what he or she really needs. Another benefit, and probably the most important if you are going to be running Lifetype in a multi-user environment, is that you can safely allow users to develop their own templates without having to worry about what they could end up doing, if they were using native php code. Also, the template rendering engine uses a much simpler syntax than php, and there is no need to confuse people making them learn another language if what they want is to change the aspect of their site a little.

A good starting point to learn about Smarty is their crash-course: http://smarty.php.net/crashcourse.php Or if you want more details, a very nice manual is also available: http://smarty.php.net/manual/en/

From a developer's point of view, because PHP allows to mix html code and php code in the same file, it is very easy to fall into the temptation of mixing it all together, resulting in an unmaintainable and unreusable amounts of code. Using templates to separate content and program logic allows us to easily reuse code in the future, and to clearly tell the difference between what is handling the presentation layer from what is handling the logic/business layer. Of course there is a slight performance penalty when using templates, but that comes at a cost that we are willing to assume and can be reduced using the advanced caching features provided by our template engine.

Lifetype uses the Smarty template engine for output rendering purposes, so first of all we should become at least familiar with it. The best place to start, is the Smarty manual. Basically, Smarty only processes text that are surrounded by the '{' and '}' characters. That text has to be meaningful to Smarty or else we will get template compilation errors. Smarty has some internal built in functions but, in terms of Lifetype, we will be using PHP objects exported to the template from the inner code, so that we can perform operations on them. Most of the time, the only thing we will have to do is call some of the methods of the objects to query some values. top

How templates work

As we said above, Lifetype uses Smarty to render the contents of your journal. That means that we can easily change the way the site looks like just by going to the Administration Interface of our journal and selecting a new set of templates. But, how does that work? How can we develop our own set of templates?

To start with, we need to know where templates are located in our system. Templates are located under the folder *templates/* in our Lifetype installation. However not all the folders we can find there are template sets we can use, since we also use that folder to store the templates for the administration interface, the wizard, our RSS feed, the email notification template and the summary page feature. So, we are left with the folders default/, standard/, and a few more. We will be basing this guideline using the grey template as an example. A quick look into the standard/ folder will reveal the following files:

 archives.template
 commentarticle.template
 commentform.template
 error.template
 footer.template
 header.template
 main.template
 post.template
 postandcomments.template
 posttrackbacks.template
 album.template
 albums.template
 resource.template
 searchresults.template


From these files, the ones in bold (commentarticle, error, linktracker, main, postandcomments, posttrackbacks, album, albums,resource) are the basic ones and the ones that drive Lifetype and control the blog's look and feel.

main.template

Controls the main page, where -normally- posts are shown.

postandcomments.template

This template is used when showing a post. Normally, you'll show the post itself here (topic, who posted it, date, text, etc) and also all the comments it has.

commentarticle.template

This template only shows a form where you can add a new comment to an article. The article could also be shown here but by default it is not.

posttrackbacks.template

This template is used to show all the trackback links available for a given post. In the default implementation only the list of links is shown, but more information regarding the trackbacks could be shown, as well as more information about the post.

error.template

As the name suggests, it is used when an error has to be reported to the user. It does not need to be modified unless necessary, since its default form works fine.

album.template

Shows the contents of a resource album.

albums.template

Shows all the top level albums of a page (the ones that have no parent album and therefore, sit on top of the album hierarchy)

resource.template

Shows a given resource, perhaps some information about it and its preview (if available)

searchresults.template

Whenever a search is performed in the system, this template will be used to show the results to users.

Other templates

So what about the other "not mandatory" templates? Well, the reason for their existence is to make life easier for us. The template files introduced so far represent complete pages. That is, each one of them has to have its header, its columns with sections, its footer and so on. The first idea would be to copy and paste the same stuff as many times as we need. But what happens if we want to make a change to the header? Do we also have to make the same change six times?

Fortunately, Smarty allows us to use file "include", via the {include ...} tag. This tag accepts one parameter, "file", which we have to set to the name of the file we would like to include. The first and easiest way to use this feature is to put all the content related to the header in one file and the content related to the footer in its own file as well. After that, replace the code for the header and the footer in the templates by the following:


{include file="$blogtemplate/header.template"}
...
template contents
...
{include file="$blogtemplate/footer.template"}


One thing that must be noted is that the path is relative to the templates/ folder but there is no need to know in which folder our template set will be installed. We can use the predefined variable $blogtemplate in the path to the included file for easier transportation of our templates between different folders, if needed.

Now, whenever we want to make a change to the way the header looks like, we only need to make that change once and since it is in a file that is used by all the other templates, the same change will be used everywhere

Therefore, and for the same reason, we have the commentform and post templates:

- commentform.template: This template simply renders a form used to send new comments to a post. It was decided to move to an included file since it is used in a couple of different places. So, using the same idea as the header and footer files, it is best to have it here and make changes only to one place. - post.template: This template shows the content of a post. In the grey template it is included in the main and postandcomments templates.

When developing your own templates, this guideline can be useful to make things easier but they are not mandatory, so feel free to use your own ideas!

Template Packages

In order to make the handling of templates easier, templates can be managed from within the administration interface. Templates can also be uploaded as packages with a special format since uploading all the files that make up a template, one by one, would be a too cumbersome process.

The only thing that makes this "template packages" special is that first of all, they are compressed and second of all, that they follow a specific directory structure. Regarding the directory structure, let's assume that our brand new template set is called, very originally indeed, "new-template". The directory structure is very simple and it has to look like this:


   new-template/
            main.template
            postandcomments.template
            error.template
            posttrackbacks.template
            commentarticle.template
            albums.template
            album.template
            resource.template
            searchresults.template

The main thing is that all the files are under a folder which is the identifier that will be used to refer to the template set. That is very important otherwise Lifetype will not be able to correctly install the file.

Once we have finished the template set and we have the files residing under the right folder, it has to be packed in order to make it easier to upload. Lifetype supports ZIP files, TAR.GZ and TAR.BZ2 files as long as the tools unzip, tar, bzip2 and gzip are available in the hosting server and that we have correctly configured support for them in the configuration panel.

The file must have the same name as the template set, which is also the same name that the folder inside the packed file will have. Once the file has been uploaded, Lifetype will perform some checks on it to make sure that it is a valid template set. It will check if the files can be found under the correct directory within the package and it will also make sure that all the core files, required for the template are there (please see previous section for more information on that) Additionally, if the administrator has blocked certain kind of files, the package will also be scanned to make sure that no files of that kind(s) can be found in the package.

Needless to mention, the main folder where locale files will be stored has to be writable by the same user used to run the web server.

Objects and variables available to templates

While looking at the content of the files that make a theme/style/layout/design, you will surely notice things like {$post->getTopic()}, {$calendar} or {$utils->postPermalink($post)}. All these things are special objects that have been "exported" to the template and that can be used there. As mentioned in the introduction to this section, one of the advantages of using a template system is that we only make available to the templates whatever is needed in the specific case of a template. Therefore, we need to know which objects are available to each of our basic templates even though there is a set of objects that is available to every template.

Template-specific objects and variables

  • main.template
    • $posts: Array of posts with the posts for the front page.
  • postandcomments.template
    • $post: The post we're showing now. * $comments: An array of comments related to this post
    • $prevpost: A post object representing the next post in the database, if any.
    • $nextpost: Another post object representing now the previous post in the database, if any.
  • commentarticle.template
    • $post: The post we're going to comment on.
  • posttrackbacks.template
    • $post: The post from which we are getting the trackback information.
    • $trackbacks: An array of trackback information objects representing the trackbacks received for this post.
  • error.template
    • $message: An string with the error message.
  • searchresults.template
    • tbd
  • albums.template
    • $albums
    • $album
  • resource.template
    • $resource
    • $albums

Globally available objects and variables

The following template objects are available to all the templates:

  • $blog: An object containing information about the current blog, such as the name and description.
  • $locale: Provides methods to translate strings based on the current locale. It also formats dates and numbers.
  • $calendar: A string containing HTML code representing the calendar. It can be customized via CSS stylesheets.
  • $archives: An array representing links to the archives. Each item represents a valid url pointing to the archives for that month. Archives are sorted chronologically, newest first, by months.
  • $recentposts: An array of post objects that contains the most recent posts made in the blog.
  • $articlecategories: An array of category objects with all the different categories availables.
  • $mylinks: Cotains a list with all the links that have been set up for this blog.
  • $utils: Provides commodity methods to generate urls and other information.
  • $rss: An RSS aggregator. See How to use the RSS aggregator for more information on this object.

Methods available in the $url object

The $url object is called a request generator, meaning that it can generate requests (URLs, in fact) regardless of the url format chosen for our blog. In other words, it prevents the inclusion of hard-coded URLs in our templates.

There is a reference list of all the methods available in this object here

Finally, it is also advisable to have a look at one of the template sets that comes with the main distribution of Lifetype.

Adding custom template files

Maybe in the future we would like to use Lifetype to completely control our personal web site, our personal journal being the main page, and adding some static sections such as our resumé or information about our hobbies, just to name a few examples. However if we add those sections as plain static html files, we will not be able to keep the same look and feel as any other page rendered/displayed by Lifetype.

This is where the templating system comes in handy. Smarty allows any static content on your site to be rendered/displayed just like the rest of the sections that are controlled by Lifetype with relative ease and does not require much editing to make it work, especially if the template you are using is modular by structure.

We will use the "grey" template as an example with the premise of adding a resumé to the site. We will have to create a new file in the templates/standard/ folder. Trying to be very original, we will call the file resume.template, please note that the .template extension is mandatory, otherwise the template engine will produce an error similar to the one below:


 Exception message: Smarty error: unable to read template resource: "standard/resume.template"
 Error code: 512
 -- Backtrace --
 ...

Template files must also have the right permissions (at least read access) for the template engine to read them. This would mean that the resume.template file needs to have at least the following file permission/attribute -r--r--r--. By default, most webservers will set newly created files with read access, however if you get a 403 error while testing out your new file, use your FTP client or Shell access to perform a "chmod 644 name_of_file" command to set the read access

Since the file is now processed as any other template, we can include Smarty code in it. But the most important thing now is that we will have access to the objects that are available to all the templates. Using the example of our resumé and assuming that all we want is to show the same sections, calendar, columns, etc so that it looks exactly like the front page while adding our own content, all we need to is include the header and the footer. The content of our resume.template file will look like:

  {include file="$blogtemplate/header.template"}
   <h1>My Resume</h1>
   <p>
    <b>Objective</b>
    Software engineering position...
    ...
   {include file="$blogtemplate/footer.template"}

Once we have finished typing our resume and we have included the header and the footer, we need to make Lifetype render it!

The templatePage() method will generate generate the right URL pointing to this customized page. This method takes into accout the current URL format settings so that we do not have to worry whether we are using custom URLs, plain URLs or whatever other URL format we might define. Therefore, in order to generate a link to our new custom template page, we only need to use the following bit of code:

<a href="{$url->templatePage("resume")}">My CV on-line</a>

There is no need to include the ".template" extension when using this method.

If we have followed these simple steps correctly, we should be seeing now our resume with the same look and feel as the page.

It is worth mentioning that there is no limit on how many custom template files we can add. Regarding security, the template engine will only look for templates in the style folder, and will not accept values for the show that contain '.', '..' or even '/'.

An interesting trick that could be used here is to name our custom templates something like templatefile.html.template. Since the .template extension is not needed in order to make the Lifetype template engine to render the file, if we use the search engine friendly mode the URL used to fetch this custom template will be:

 http://domain.of.your.site/static/X/templatefile.html

Now that looks like a normal, plain and static HTML file when in fact it is being rendered by Lifetype. However this trick is not so useful when using normal plain URLS.

My Resume

Objective Software engineering position... ... {include file="$blogtemplate/footer.template"} </pre> Once we have finished typing our resume and we have included the header and the footer, we need to make Lifetype render it! The templatePage() method will generate generate the right URL pointing to this customized page. This method takes into accout the current URL format settings so that we do not have to worry whether we are using custom URLs, plain URLs or whatever other URL format we might define. Therefore, in order to generate a link to our new custom template page, we only need to use the following bit of code:

<a href="{$url->templatePage("resume")}">My CV on-line</a>

There is no need to include the ".template" extension when using this method.

If we have followed these simple steps correctly, we should be seeing now our resume with the same look and feel as the page.

It is worth mentioning that there is no limit on how many custom template files we can add. Regarding security, the template engine will only look for templates in the style folder, and will not accept values for the show that contain '.', '..' or even '/'.

An interesting trick that could be used here is to name our custom templates something like templatefile.html.template. Since the .template extension is not needed in order to make the Lifetype template engine to render the file, if we use the search engine friendly mode the URL used to fetch this custom template will be:

 http://domain.of.your.site/static/X/templatefile.html

Now that looks like a normal, plain and static HTML file when in fact it is being rendered by Lifetype. However this trick is not so useful when using normal plain URLS.

Understanding the template load order

When the LifeType template engine is requested to load a template file called main.template, the parameter template_load_order that can be found under Administration->Settings->Templates will determine whether how this file is loaded:

  • If set to user template first, the current template folder (be it a custom user template or a global template) is checked first and if the file is not found, then the engine will try to load the file templates/default/main.template.
  • If set to global template first, the engine will try to load templates/default/main.template first and if not found, it will attempt to load the same file from the current template set.

This feature allows site administrators to override some templates with global versions, or to provide fallback options in case users are using incomplete templates.

The folder where global templates are be stored is templates/default/ and it cannot be changed.

Using the global comment form

Out of the box, LifeType uses this feature to provide a global commentform.template. None of the templates provided by the LifeType project provide their own commentform.template and rely instead on the global one. This allows site administrators to easily modify this form to add anti-spam measures (such as the 'authimage' plugin), and get these changes implemented in all blogs accross the same site.

This means that templates should be adapted so that the global commentform.template fits well into the style of the template. The global commentform.template provides a set of CSS identifiers that can used to modify its appearance:

  • CommentForm: This is used by the
    tag that contains the whole form. You can use this as a selector to refer to any of the elements inside the form as in #CommentForm input {...}.
  • NewComment: This is the identifier of the <form> tag itself.
  • commentTopic: Identifier assigned to the input field used to enter the comment topic.
  • commentText: Identifier assigned to the input field used to enter the comment text.
  • userName: Identifier assigned to the input field used to enter the commenter's name.
  • userEmail: Identifier assigned to the input field used to enter the commenter's email address.
  • userUrl: Identifier assigned to the input field used to enter the commenter's own link.
  • Submit: This is the identifier of the
    tag that contains the submit button.
  • Add: This is the identifier assigned to the submit button.
  • authImage: Additionally, the global comment form comes with support for the authimage plugin out of the box, so all administrators have to do is enable the plugin in the admin interface and it will be automatically displayed in all users' blogs.

Custom Summary templates

It is also possible to create custom pages for the summary page that share the same look and feel, in a very similar way to which custom pages are added to blog template sets.

As an example, we are going to add a FAQ page to our summary.

First of all, we will create a file called faq.template in the templates/summary folder with the following contents:

{include file="summary/header.template" selected="faq" columns=1}
<div id="onecolumn">
    <h2>Frequently Asked Questions</h2>
    <h4>What is this?</h4>
    <p>
     This is a blogging site
    </p>
    <h4>How much does it cost?</h4>
    <p>It's free!</p>
    ...
{include file="summary/footer.template"}

Now we should place a link to this page. In order to do so, the correct URL to this page should be

http://www.yoursite.com/summary.php?op=display&page=faq

The value of the "op" parameter must always be display. The value of the page parameter must be the name of the template file that we would like to show but without the .template extension.

If we would like to show a link to the FAQ page at the top menu bar of the default summary page, this is what we should do:

 <div id="menubar">
<div id="menu">
<ul class="menuTop">
<li class="menuOption"><a href="?op=Summary" title="Main Page">{$locale->tr("all")}</a></li>
<li class="menuOption"><a href="?op=RegisterStep0">{$locale->tr("register")}</a></li>
<li class="menuOption"><a href="?op=BlogList">{$locale->tr("blogs")}</a></li>
<li class="menuOption"><a href="?op=UserList">{$locale->tr("users")}</a></li>
<li class="menuOption"><a href="summary.php?op=display&page=faq">{$locale->tr("summary_faq")}</a></li>
</ul>
</div>
</div>

Since the summary.php script does not support "prettier" URLs, it is possible to create a simple mod_rewrite rule to rewrite something like http://www.yoursite.com/summary/faq to http://www.yoursite.com/summary.php?op=display&page=faq

An universal way to show an arbitrary page as a HTML-page is including the following code into your .htaccess:

#Static sites for summary page. Normally the next 2 lines are activated in your default .htaccess. If not, remove the '#'. Add the code after this lines.
#RewriteEngine On
#RewriteBase /

RewriteRule ^(.*)\.html$ /summary.php?op=display&page=$1

If you have added the template to your /templates/summary folder (like the 'faq' sample above), you can call any site with:

http://www.yoursite.com/anysite.html

Retrieved from "http://wiki.lifetype.net/index.php/Template_Development"