Smart templating with Movable Type
A little while ago I converted my site to use the Smarty for dynamic templating. I'm still using Movable Type for the content management though. Click the 'more' link for an overview of how it all works together...
Smart Templates
The Smarty template engine for PHP is pretty sweet. There's a lot of power in dynamic template rendering. The most important for me is that I can change the shape of my template at any time and the changes are reflected instantly throughout my site.
Getting Movable Type to play nice with Smarty isn't too difficult either. I just converted my "Individual Archive" template to look like this:
<?php
<MTInclude module="Entry to PHP Hash">
if (!$SILENT_MODE) {
include_once('/www/bradchoate/html.php');
smartyRender($entry, 'entry.tpl');
}
return $entry;
?>
The "Entry to PHP Hash" template module populates a PHP hash variable (named $entry), and looks like this:
$entry['id'] = <$MTEntryID$>;
$entry['permLink'] = '<$MTEntryLink encode_php="q"$>';
$entry['title'] = '<$MTEntryTitle encode_php="q"$>';
<MTEntryNext>
$entry['nextLink'] = '>$MTEntryLink
encode_php="q"$>';
$entry['nextTitle'] = '<$MTEntryTitle
encode_php="q"$>';
</MTEntryNext>
<MTEntryPrevious>
$entry['prevLink'] = '>$MTEntryLink
encode_php="q"$>';
$entry['prevTitle'] = '<$MTEntryTitle
encode_php="q"$>';
</MTEntryPrevious>
$entry['catLink'] = '<MTIfNotEmpty
var="EntryCategory"><a href="<$MTEntryLink
archive_type="Category"$>"><$MTEntryCategory
encode_php="q"$></a></MTIfNotEmpty>';
$entry['body'] = '<$MTEntryBody encode_php="q"$>';
$entry['more'] = '<$MTEntryMore encode_php="q"$>';
// -500 for EST timezone
$entry['date'] = '<$MTEntryDate
format="%Y-%m-%d %H:%M:%S"$><MTBlogTimezone
no_colon="1">';
$pings = array();
<MTEntryIfAllowPings>
$entry['canPing'] = 1;
$entry['trackBackData'] = '<$MTEntryTrackbackData
encode_php="q"$>';
$entry['trackBackLink'] = '<$MTEntryTrackbackLink
encode_php="q"$>';
<MTPings>
$pings[] = array(
'id' => <$MTPingID$>,
'link' => '<a target="new" href="<$MTPingURL
encode_php="q"$>"><$MTPingTitle
encode_php="q"$></a>',
'excerpt' => '<$MTPingExcerpt encode_php="q"$>',
'blog' => '<$MTPingBlogName encode_php="q"$>',
'date' => '<$MTPingDate
format="%Y-%m-%d %H:%M:%S"$><MTBlogTimezone
no_colon="1">'
);
</MTPings>
</MTEntryIfAllowPings>
$entry['pings'] = $pings;
$comments = array();
<MTEntryIfAllowComments>
$entry['canComment'] = 1;
<MTComments>
$comments[] = array(
'body' => '<$MTCommentBody
encode_php="q"$>',
'link' => '<$MTCommentAuthorLink
encode_php="q"$>',
'date' => '<$MTCommentDate
format="%Y-%m-%d %H:%M:%S"$><MTBlogTimezone
no_colon="1">'
);
</MTComments>
</MTEntryIfAllowComments>
$entry['comments'] = $comments;
The 'html.php' file included above has a function called smartyRender and another called Smarty (for creating the Smarty object itself). It looks like this:
function Smarty() {
require_once('Smarty.class.php');
global $SMARTY;
if (!$SMARTY) {
$SMARTY = new Smarty;
$SMARTY->template_dir = '/www/bradchoate/templates';
$SMARTY->compile_dir = '/www/bradchoate/templates_c';
// set compile_check to '1' when you're playing
// with your templates:
$SMARTY->compile_check = 1;
}
return $SMARTY;
}
function smartyRender($object, $tmpl) {
$smarty = Smarty();
$smarty->assign($object);
$smarty->display($tmpl);
}
Now, my actual Smarty template ('entry.tpl') refers to elements defined in my MT template like this:
<title>[brad choate dot com] {$title}</title>
For loops like the comments, you use a {section} marker. Like this:
{section name=comment loop=$comments}
{$comments[comment].body}
<div class="blogPosted">
from {$comments[comment].link} @
{$comments[comment].date|date_format}
</div>
{/section}
The 'entry.tpl' template module is linked to a physical file, so as soon as I edit and save my entry.tpl template from within MT, the changes across my individual archives are immediate since they're dynamically rendered with Smarty. There's also some space savings here. Storing JUST the data for each individual file is more efficient than having all the HTML markup within each file.
The '$SILENT_MODE' variable used in my individual archive template allows me to control whether or not the individual archive file automatically renders itself or not. This allows you to access individual entries and retrieve that hash that they create. Like so:
$SILENT_MODE = 1;
$entry = include("/www/bradchoate/past/000001.php");
You can then apply any template you'd like using the data:
smartyRender($entry, 'some_other_template.tpl');
Well, I hope all that makes sense. It's a little more complicated, but the extra flexibility and convenience it provides is worth it.
Thanks for that explanation Brad!
I have thought weeks about Smarty templates for MT! (just did not have the guts, but now I wil follow...)
Lawrence
Excelent, Brad!
I've been configuring my MT Blog and sometimes templates can be a real pain in the neck. I saw your macro plugin, and one thing led to another. I have seen your article and I hope you don't mind me using your ideas for my site. :)
Congratulations for this explanation, Brad.
I'm using FastTemplate as my template engine now, but I'm going to change it for Smarty when I finish the redesign of my site. And this explanation make it easy.
I'm thinking to add a section to my blog with MovableType tips, and I'd like to add this explanation if you give me permission to translate it to spanish.
Regards.
"machiavelli"
Hi,
I would like to know how to use the dynamic template_dir and how i will know whether that file is cached or not by is_cached.
My problem is I have 2 templates for a single file like cv.php in template/cv1.tpl template/cv2.tpl based on language like php is cv1 template and perl is cv2 template. when i execute cv.php i need to specify the template name for is_cached as parameter. How can I do??
Brad
Again a fabulous article that really helped me break the back of getting Smarty working with MT (still only on a test version of the site though).
One thing that I found - your html.php fragment above doesn't work as written with PHP4 because the include_once() statement (in the MT template) pops the PHP interpreter back into HTML mode. If you add an opening less-than?php and a closing ?gretater-than all is fine... keep up the good work!!!
It works for me because my "html.php" is just a bunch of PHP functions (it starts with <?php and ends with ?>). smartyRender is one of those functions.
Excellent idea, Brad. I've considered doing this same thing many times and yet never considered doing in this way. Thank you.
A note for mt beginners (like me): remember you'll need to change the weblog configuration preferences for 'File extension for archive files' from 'html' to 'php'.
if i set up smarty with movabletype on a site i help run, could it also take care of the mailman subscribe and admin pages?
Great tut :)
for comments a {foreach ..} may be better to display all comments even if one of them is deleted.
{foreach from=$comments item=comment_id}
{$comment_id.title}{$comment_id.body}
{/foreach}