Customizing Graffiti CMS, part III

(In which I continue taking apart a Wordpress theme to make it work with Graffiti. Part I. Part II. Part IV. )

Last time I'd set up the layout.view file and completed it by adding the @childcontent statement. Now I need to think about the other two main view files, index.view and post.view, the ones that will supply the child content.

The index.view file is possibly the easiest at this stage, since we started out with analyzing the equivalent PHP file from the Chronicles theme.

The index.view file is meant to display a list of posts. This list could come from a search, from a category list, from a tag list, and so on. No matter what the source, the view must display the post title, date, author, category, tags, and the first few words from each post. The way Graffiti works is that the list will have a maximum of 10 posts in it, and so we shall need to consider the paging facilities in Garffiti since after a while it's likely that there will be more than 10 posts to display.

So, all in all, there's a lot to consider.

The way I constructed the layout.view file, the content view files are responsible for deciding whether they want to display none, one, or both sidebars, and then displaying them. The sidebars are rendered by Chronicles as

<?php include (TEMPLATEPATH . '/sidebar1.php'); ?>

So, all we need to do is (roughly) the same for Graffiti:

$macros.LoadThemeView("sidebarleft.view")

After changing the PHP code in sidebar1.php to sidebarleft.view I had this:

   1: <div id="sidebar1">
   2:     <div id="sidebar1_top"><!-- Hack for IE --></div>
   3:     <ul>
   4:         $macros.LeftSideBar("%{beforeWidget='<li class=\"widget\">', afterWidget='</li>', beforeTitle='<h2>', afterTitle='</h2>'}")
   5:     </ul>
   6:     <div id="sidebar1_bottom"><!-- Hack for IE --></div>
   7: </div><!--end of sidebar1 -->

Similarly for the right sidebar:

   1: <div id="sidebar2">
   2:     <div id="sidebar2_top"><!-- Hack for IE --></div>
   3:     <ul>
   4:         $macros.RightSideBar("%{beforeWidget='<li class=\"widget\">', afterWidget='</li>', beforeTitle='<h2>', afterTitle='</h2>'}")
   5:     </ul>
   6:     <div id="sidebar2_bottom"><!-- Hack for IE --></div>
   7: </div><!--end of sidebar2 -->  

The nice thing about the $macros methods that render the sidebar is that you can specify the HTML tags that go around the widget "content" and around the widget titles. I'll talk at another stage how to write a sidebar widget.

Now we have some PHP code that iterates through the posts:

   1: <?php if (have_posts()) : ?>
   2: <?php while (have_posts()) : the_post(); ?>

Graffiti's Chalk language has a foreach loop construct which will nicely replace this. The loop has the following syntax:

   1: #foreach($post in $posts)
   2:   #each (this is optional since it’s the default section)
   3:        <!--text which appears for each item-->
   4:   #before
   5:        <!--text which appears before each item-->
   6:   #after
   7:        <!--text which appears after each item-->
   8:   #between
   9:        <!--text which appears between each two items-->
  10:   #odd
  11:        <!--text which appears for every other item, including the first-->
  12:   #even
  13:        <!--text which appears for every other item, starting with the second-->
  14:   #nodata
  15:        <!--Content rendered if $items evaluated to null or empty-->
  16:   #beforeall
  17:        <!--text which appears before the loop, only if there are items matching condition-->
  18:   #afterall
  19:        <!--text which appears after the loop, only of there are items matching condition-->
  20: #end

As you can see, this a very rich for loop, geared to producing rich visual displays of lists.

The $posts list id provided by Graffiti when the view is rendered. The $post variable is defined by us, and we can call it what we want. It'll be used within the loop to expose the various interesting properties of the post itself.

   1: $post.Body -- the body of the post
   2: $post.CreatedBy -- the user who created the post
   3: $post.Url -- the site's url to the post
   4: $post.Title - the title of the post
   5: $post.Published -- the date/time that the post was published
   6: $post.CommentCount -- the number of comments for the post

From these properties and from the Chalk foreach loop we can convert the PHP code and HTML formatting to a Graffiti view.

   1: #foreach($post in $posts)
   2:   #each
   3:     <div class="post" id="$post.id">
   4:  
   5:       <div class="date">
   6:         $post.Published.ToString("MMM dd yyyy")
   7:       </div><!--end of date -->
   8:  
   9:       <div class="post_title">
  10:         <h2><a href="$post.Url" rel="bookmark" title="$post.Title">$post.Title</a></h2>
  11:         <div class="posted">
  12:           Posted by $post.CreatedBy at $post.Published.ToString("h:mm tt")
  13:         </div><!--end of posted -->
  14:       </div><!--end of post_title -->
  15:  
  16:       <br clear="all" />
  17:  
  18:       <div class="tags">$macros.TagList($post.TagList)</div><!--end of tags -->
  19:  
  20:       $post.Excerpt("<p>", "</p>" ,"Read more...", 300)
  21:       
  22:       <div class="meta">
  23:         Filed under : $macros.CategoryLink($post.Category) | $macros.CommentUrl($post, "%{anchor='comments'}")
  24:       </div><!--end of meta -->
  25:     </div><!--end of post -->
  26:  
  27:   #nodata
  28:     <div class="post">
  29:       Sorry, there are no posts matching your request.
  30:     </div>
  31:   
  32:   #end

The code to add paging is simplicity itself, although to my taste a little too simple since we cannot change the text that will be shown when there is a previous or next page of posts (the text is hard-coded in Graffiti.Core.dll). The one and only parameter is the CSS class name for the div that contains the previous/next paging links.

$macros.Pager("navigation")

(UPDATE: Scott Watermasysk informs me in the comments below that there is an overload that does allow you to set the previous/next paging link text:

$macros.Pager(CssStyle, PreviousText, NextText)

I've altered the calls to paging in my view files.)

Next time, we'll look at the final piece of the theme conversion puzzle.

Loading similar posts...   Loading links to posts on similar topics...

3 Responses

 avatar
#1 Scott Watermasysk said...
02-Dec-08 6:36 AM

Hi Julian,

Great series of posts. We will improve on the documentation.

For the pager, there is a $macros.Pager overload which lets you pass in the previous/next text: $macros.Pager("cssName", "previous", "next)

If you wanted even more control, you could potentially write a custom extension which calls Graffiti.Core.Util.Pager(...) as well.

HTH,

Scott

julian m bucknall avatar
#2 julian m bucknall said...
07-Dec-08 8:09 PM

Scott:Thanks for the hint: I've already applied it -- and updated the post.

Cheers, Julian

 avatar
#3 zhaojc said...
01-Jan-10 6:52 AM

where is the similar topics module?

Leave a response

Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.

  •  Emphasize with italics: surround word with underscores _emphasis_
  •  Emphasize strongly: surround word with double-asterisks **strong**
  •  Link: surround text with square brackets, url with parentheses [text](url)
  •  Inline code: surround text with backticks `IEnumerable`
  •  Unordered list: start each line with an asterisk, space * an item
  •  Ordered list: start each line with a digit, period, space 1. an item
  •  Insert code block: start each line with four spaces
  •  Insert blockquote: start each line with right-angle-bracket, space > Now is the time...
Preview of response