The Templates Behind The New Blog Engine

I recently opted to throw together my own blog software (after going through the standard Build or Buy analysis), expediting deployment as a means of forcing follow-thru. The goals of this micro-project were to improve the authoring and content management experience, to improve searchability of the content (without having to cast content out from the blog to a static form), and to improve the usability and navigation from the user’s perspective (for instancethe classic “date” navigator common on most blogs is something that I’ve opted to remove).

Despite having close to no time to allocate to this task, my tendency to over-engineer still showed through: The easiest option would have been a content-management system defined entirely in code (it’s as easy for me to change and deploy code than it is to change templates and metadata), and of course to build it for a single author. Instead it supports many blogs through the same URLRedirector, blog aggregations (where a blog is a publication of a set of blogs, each with distinct authors) each using its own templates and configurations.

Which brings me to templates — failing to find a decent Smarty-type templating system for .NET (basic ASPX is really a templating system, but I’m speaking more towards something that can enumerate sections, retrieving data based upon an object structure of relationships and containment).

So I had to build a basic templating system, yielding the templates that follow. The first for HTML output–

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta><title>{#blog.Title} {#docTitle}</title><link rel="stylesheet" type="text/css" media="screen, projection"    href="http://www.yafla.com/dforbes/style/css/blog.css"></link><script type="text/javascript" src="http://www.haloscan.com/load/dforbes"> </script></head><body><div class="clsHeader"><div class="clsBlogHeader"><a href="{#blog.BaseUrl}">{#blog.Title}</a></div><div class="clsSubheader">{#blog.Description}</div></div><div class="clsBody">{foreach $entry in $entries}<div class="clsEntry">   <div class="clsDate">{#entry.EntryContent.PublishDateUTC|dddd, MMMM dd yyyy}</div>   <div class="clsTitle"><a href="{#entry.Permalink}">{#entry.EntryContent.EntryTitle}</a></div>   <div class="clsBody">{#entry.EntryContent.EntryContent}</div>   <div class="clsKeywords">{foreach $keyword in $entry.EntryKeywords}&nbsp;      <a href="{#blog.BaseUrl}{#keyword.KeywordText|escape}">{#keyword.KeywordText}</a>&nbsp;{/foreach}   </div>   <div class="clsPermalink">      <a href="javascript:HaloScan('{#entry.MappingId}');" target="_self">      <script type="text/javascript">postCount('{#entry.MappingId}'); </script></a>&nbsp;      <a href="{#entry.Permalink}">permalink</a>   </div>{foreach $relatedentry in $entry.RelatedEntries}{ifcond $LoopFirst = "True"}<center><div class="clsRelatedEntries">Related Entries{/ifcond}<div class="clsRelatedEntry">   <a href="{#relatedentry.Permalink}">{#relatedentry.EntryContent.EntryTitle}</a></div>{ifcond $LoopLast = "True"}</div></center>{/ifcond}{/foreach}</div>{/foreach}<div class="clsAdBlock">{#adBlockHorizontal}</div><div class="clsNavigator">   <span class="clsNavigateEarlier">{#moveEarlier}</span><span class="clsNavigateLater">{#moveLater}   </span></div></div><br/><div class="clsAttribution">   <a href="mailto:{#entry.EntryContent.ContentAuthor.EmailAddress}">      {#entry.EntryContent.ContentAuthor.Name}   </a> -    {#entry.EntryContent.ContentAuthor.Description}</div></body></html>

The next template is for RSS consumers–

<rss version="2.0">  <channel>    <title>{#blog.Title|escape}</title>    <link>{#blog.BaseUrl}</link>    <description>{#blog.Description|escape}</description>    <lastBuildDate>{#buildDate|r}</lastBuildDate>    <language>en-us</language>		{foreach $entry in $entries}		<item>		  <title>{#entry.EntryContent.EntryTitle|escape}</title>		  <link>{#entry.Permalink}</link>		  <guid>{#entry.Permalink}</guid>		  <pubDate>{#entry.EntryContent.PublishDateUTC|r}</pubDate>		  <description><![CDATA[{#entry.EntryContent.EntryContent}]]></description>		</item>		{/foreach}  </channel></rss>

All in all, I think it works pretty good, and I can successfully run the W3C validations on the vast majority of generated pages and get the comforting green checkmark.