Dennis Forbes on Pragmatic Software Development
Subscribe to RSS
 
Tuesday, November 06 2007

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 instance the 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.

Reader Comments

NICE!!!!

Luv the clean layout

Please keep it like this, and keep up the excellent content
Rosie @ 11/6/2007 2:14:56 PM
Are these templates out of date? The Related Entry section seems to alternate colors, but the template doesn't seem to have that feature.
Jibba Jabba @ 11/6/2007 2:34:42 PM
You need a better way to get to historical content
CoT Crew @ 11/6/2007 2:35:53 PM
I am a big fan of your content Dennis, but you post way too seldom. Please post more even if the quality isn't as high. Pretty please.
Warren Shaw @ 11/6/2007 2:47:05 PM
Your rss.xml file doesn't render correctly under IE7. There is a problem with markup as everything is rendered as multiple links
Sébastien Mouren @ 11/6/2007 2:51:17 PM
Jibba Jabba,

>Are these templates out of date? The Related Entry section seems to alternate colors, but the template doesn't seem to have that feature.

Good catch! Earlier today I modified the entries to use an alternate line style for alternate rows. I just haven't updated the entry to reflect this yet.

Sébastien,

You are absolutely correct, and I apologize -- when I migrated to the new system, one change was that I altered the guid to point to the new, textual links. RSS readers use this identifier to figure out what is old and what is new, so for any content that was migrated over (everything prior to the last two) readers see the old entries with the new GUID and think they're newly published content.

I apologize for that (I tried for 100% backwards compatibility, but that was one area where I thought it would be cleaner to just move to the new URLs), and it shouldn't occur for any new entries.

Sorry for that.
Dennis Forbes @ 11/6/2007 3:08:50 PM
Your template has a lot of similarities to Smarty...was that intentional?

I love the new look, and it seems fast and full featured. Thanks
John Leyton @ 11/7/2007 5:58:48 AM

Add Comment

Name *:

Email Address:

(your email address is not displayed)
Website:

Comment *:


Dennis Forbes - Dennis Forbes is a Toronto-based software architect and technology writer