Creating a Mephisto Theme using Liquid

10 October 2007, 20:51, by Jon

Mephisto is an excellent blogging platform written in Ruby on Rails by Rick Olsen and Justin Palmer both of whom are behind the excellent Lighthouse Issue Tracking Software . This article / tutorial takes you step by step through the process of creating a custom theme / templates.

To an extent I am going to assume you are already familiar with Ruby and the Rails Web Development Framework, but where possible I hope to keep things as simple as possible.

First of all one of the best ways to go about learning how to create a custom template / theme is to download one of the existing themes you like from the Mephisto Themes Gallery and look inside the .zip file and see how these template authors have gone about implementing their themes.

To get started you will need a copy of Mephisto to test your themes against. You can easily checkout the latest version from subversion. Follow the instruction from the Mephisto Site . Mephisto themes are stored under the /themes/ directory in your Rails application root. If you have a default single host installation, you need to create a new empty folder under /themes/site1/ . You can call the folder whatever you like, this is where we will create our theme.

Mephisto themes are made up of Liquid template files (basically html files with extra markup tags to inject content into your template), images used by your template as well as CSS stylesheets and Javascript files.

Understanding liquid files

Liquid files were created by the developers at Shopify so that their users could customize their shops. These templates work exactly as Rails .rhtml files do however they are safe in the sense that if a variable is nil or undefined they don’t throw an exception or server error, they simply do not generate any content. For non Rails developers .rhtml files store the html for pages and have special <% > tags where Ruby code can be entered and <= > tags where we can output to the page. Liquid files are pretty much the same, however instead of < > tags we have { } and instead of <= %> we have {{ }} tags.

More information can be found on Shopify’s Site and I recommend you read through this, in addition to this article.

Mephisto provides a variety of variable that can be used not only to put content on the page, but also to generate the navigation links, to link between pages. For example in the template that is used to display an article such as this, we have a {{ }} tags which specify to output the article body text like this {{ article.body }}.

Iteration

If the item is an array we can loop through each element using the following:

  1. {% for blog_section in site.blog_sections }
  2. {{ blog_section.name }}
  3. { endfor %}

Conditions

We can also test the values in these Liquid variables and conditionally display content:

  1. {% if section.is_home }
  2. Welcome to the site…
  3. { endif %}

Variable Reference

Before we get into creating templates there are two places to look for the Liquid variables available in Mephisto, directly on Mephisto’s Site and also on Mephisto’s old Wiki

There are various examples on how to do things like formatting dates etc., especially in the latter link above.

Structure of Mephisto

In addition to being simply a blog, Mephisto provides a Content Management System, this allows you to create content pages, such as an about page or portfolio (At the time of writing, something I am still meaning to do ;) )

When we design a theme, we need to bear these different types of content (blog / pages) in mind.

Required Liquid Files

To make up a theme, Mephisto looks for a minimum of the following files, which need to be stored in a folder called ‘templates’ within the folder you created above under /themes/site1/. You need to be careful the folder is spelt exactly as written here as this is where Mephisto will look.

  • section.liquid – The template is used for blog sections and normally show several articles, this template is generally also used as the template for your home page.
  • single.liquid – The template used for showing a single article, often we only show short articles or excerpts in the blog sections above.
  • tag.liquid – The template used to show articles for a particular tag.
  • search.liquid – The template used to display search results.
  • archive.liquid – The template used to display articles for a particular month.
  • error.liquid – The template used to show a custom error, when an article or resource is not found.

layout.liquid

In addition to the above templates, we have an overall template which provides content for every page called layout.liquid where we can put our main look and feel. This file is located, not in ‘templates’ as above, but in a subfolder (again within out theme) called ‘layouts’.

Creating a layout template (layout.liquid)

As mentioned above, this file is located within the layouts folder in our theme folder. This file is used no matter where we are in the blog so we can use it to put any content that appears on every page, for example the header with logos and in my case my search form, our side bars and footer. This page is also the only page that holds the html head and body tags, so at a minimum we need:

  1. <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
  2. <html>
  3. <head>
  4. <title>My Blog</title>
  5. </head>
  6. <body>
  7. {{ content_for_layout }}
  8. </body>
  9. </html>

Head Section

Instead of having a static page title, we can dynamically insert the site title or if we are looking at a blog article, the article’s title is displayed. This not only gives the users a better experience but also shows as the title for search engine listings and in stats services such as Feedburner

  1. <title>{{ site.title }} {% if article } – {{ article.title }} { else } {{ site.subtitle }} { endif %}</title>

Above we are displaying the site title, and if we are viewing an article, the article object is available, so we can show the title or we show the site subtitle, as set in the Admin Settings.

We also want to make sure our RSS feed to be auto discoverable to browsers etc, so we want to add the following to our head section:

  1. {{ head.feed }}
  2. <! If you are using feed burner, set it up with your RSS feed http://yourdomain/feed then use the feedburner address >
  3. <link href=http://feeds.feedburner.com/miletbaker title=Jon Milet Baker’s Blog type=application/rss+xml rel=alternate/>

We also want to reference any external Javascript or Stylesheet files by using the following tags:

  1. {{ ‘stylesheetfilename’ | stylesheet }}
  2. {{ ‘javascriptfilename’ | javascript }}

Body Section

In layout.liquid we want to create our navigation links to access the different page or blog sections. I generally create navigation using unordered list tags , styling them using css. I can then generate the list items I need using a liquid iteration as below:

  1. <ul>
  2. {% for section in site.page_sections }
  3. <li><a href={{ section.url }}>{{ section.name }}</a></li>
  4. { endfor %}
  5. </ul>

The above, creates links to our page sections, we can also create links to the blog sections by changing line 2 to:

  1. {% for section in site.blog_sections %}

We also likely want to add a search box to every page, we want to add the following:

  1. <form method=get action=/search>
  2. <input type=text class=search value= name=q id=q size=15/>
  3. </form>

As we would likely have the side bar defined in this file we would need to use the technique we used to conditionally display the title, for conditionally displaying content in the side bar. One example for this is displaying related articles to the current article. My related articles technique lists other articles tagged with the same tags. We can do this as follows:

  1. {% if article }
  2. {{ article.tags | tagged_articles | assign_to: ‘rel_articles’}}
  3. { for rel_article in rel_articles limit: 5 }
  4. <a href={{rel_article.url}}>{{ rel_article.title }}
  5. { endfor }
  6. { endif %}

The above code only shows when an article is being displayed, we pass all the tags for the current article and send it to a Mephisto function which returns a collection of articles, which we in turn store in a variable called rel_articles.

In addition to showing related articles we can also show our archive links using the following (in this case we only want this to display in a section):

  1. {% for month in section.months }
  2. {{ section | monthly_articles: month | size | assign_to: ‘articles_count’ }}
  3. { if articles_count > 0 }
  4. <a href={{ section.path }}/{{ section.archive_path }}/{{ month | strftime: Y/m }}>{{ month | strftime: “%B %Y” }} ( {{ articles_count }} )</a>
  5. { endif }
  6. { endfor %}

You may also like to add a list of tags here. My site uses the Mephisto Tag Cloud plugin by Hank to generate different sized tag links based on their use, You could use the Technorati Widget or simply list all the site tags using:

  1. {{ site | linked_tag_list }}

Now we have a basic layout template that contains our common page content, we can get on with the individual templates.

Section template (section.liquid)

The sectiom template as mentioned before acts as the index or contents page for your blog items for each blog section, including the home section. Here you have access to not only the site level variable, but also the Section variables.

  1. {% if articles.size > 0 }
  2. <h1>Articles</h1>
  3. { for article in articles }
  4. <! Within this loop we have access to the article variables. We will need to display each article and some useful properties
  5. of the article variable are shown below:—>
  6. {{ article | link_to_article }}
  7. {{ article.published_at | date: ‘%b %d’ }}
  8. {{ article.author.login }}
  9. {{ article | linked_tag_list }}
  10. <a href={{ article.url }}#comments>{{ article.comments_count | pluralize: ‘comment’ }}</a>
  11. {{ article.body | textilize }}
  12. { endfor }
  13. { else }
  14. <p>No articles found.</p>
  15. { endif %}

Line 10 allows us to display the number of comments with a link to the part of the page where our comments are located, note the use of pluralize that automatically pluralizes the work comment, based on the number of comments, i.e. “1 comment” or “2 comments”.

Also as this is our contents page and we may have long articles rather than use the {{ article.body | textilize }} at line 11, Mephisto provides us with the functionality to write an excerpt. We can write a conditional statement that outputs the articles excerpt (if one exists) or the artilces body for shorter articles. This then requires you to Add an excerpt when writing longer articles, for example this article has all the text up to the ‘Understanding liquid files’ heading in the excerpt. The rest of the text is in the body.

We can then replace {{article.body | textilize }} with :

  1. {% if article.excerpt.size > 0 }
  2. {{ article.excerpt | textilize }}
  3. <a href={{ article.url }} >More…</a><br/><br/>
  4. { else }
  5. {{ article.body | textilize }}
  6. { endif %}

Note: I have found that the Mephisto feed outputs the article.excerpt followed by the article.body for each article. So I have found the best way to handle this is to use the excerpt to create a divider for long articles and not have the text in the excerpt repeated in the article. However it is up to you how you implement this, you could output the article excerpt for article in quotes at the top of your article, literally as an excerpt as an excerpt of the body text.

Single template (single.liquid)

The single.layout template is used to display a particular blog item. It is also used by default to display page items.

On this page we have access to the variables in the article object and want to have the following output to the page:

  1. <h1>{{ article.title }}</h1>
  2. <p>Posted: {{ article.published_at | date: ‘%d %B %Y’ }}, by {{ article.author.login }}<br/>
  3. Tags: {{ article | linked_tag_list }}<br/>
  4. Comments: <a href={{ article.url }}#comments>{{ article.comments_count | pluralize: ‘comment’ }}</a></p>
  5. {{ article.excerpt | textilize }}
  6. {{ article.body | textilize }}

Above we list the article title, when it was published and by who along with the tags. As I am using the excerpt as to separate large articles I simple output the excerpt, immediately followed by the body text. If there is no excerpt only the body text is output.

In addition to the above we will want the ability for people to add comments to our articles (and I suggest you sign up for and use Akismet).

We need to add the following code to display out comments:

  1. <a name=comments></a>
  2. {% if article.comments.size != 0 }
  3. { for comment in article.comments }
  4. {{ comment.author_link }}
  5. {{ comment.published_at | date: ‘%d %B %Y’ }}
  6. {{ comment.body | textilize }}
  7. { endfor }
  8. { endif %}

The a tag at the top is used so that when a user navigates to the article url #comments they are taken directle to the required location on the page. You can also include the Gravatar of the commentor, if they have set one up using the following tag within the for loop above:

  1. {{ comment | gravatar: 80, “/images/mephisto/avatar.gif” }}

The numeric value 80 is the size of the gravatar display, you can specify any size upto 80px

We also need to provide the user with a form to add comments if we are still accepting comments on that article, we do this as follows:

  1. {% commentform }
  2. <!- comment form ->
  3. <label for=comment_author>Nick Name</label><br/>{{ form.name }}<br/>
  4. <label for=comment_author_email>Email (optional)</label><br/>{{ form.email }}<br/>
  5. <label for=comment_author_url>Website (optional)</label><br/>{{ form.url }}<br/>
  6. <label for=comment_body>Let the thoughts flow….</label><br/>{{ form.body }}<br/>
  7. <input type=submit value=Add />
  8. { endcommentform %}

Tag template (tag.liquid), Archive template (archive.liquid) & Search template (search.liquid)

There are three ways users can find articles on your blog using Mephisto, using the tag facility to find articles tagged under a particular tag, the archive facility to find articles by date and the search facility.

All of these will generally look the same and will likely simply list page titles and dates and perhaps the body or excerpt content, as we did for the section.layout template.

In addition we may want to list the number of articles, for example using

  1. {{articles.size | pluralize: ‘article’ }} found.

Paging

Mephisto will only display the number of items on a page as specified in the Admin Settings. Unfortunately Mephisto only implements paging on the search template when used in conjunction with a search. Here we can add to search.liquid the following to allow users to navigate through the pages.

  1. {% if previous_page != “” }<a href={{ previous_page }}>< Previous Page </a>{ endif } { if next_page != “” }<a href={{ next_page }}>Next Page ></a>{ endif %}

Because the articles.size contains the number of articles to output to the page, with searches that span multiple pages, we would not display the total number of articles found. In this case we need to chnage the example above from articles.size to search_count as follows:

  1. {{search_count | pluralize: ‘article’ }} found.

Error template (error.liquid)

The final template we need to create is the error.liquid template that displays whenever the user requests an article or resource that does not exist. It is good practice to give the user options to find what they are looking for, so I like to firstly display my recent articles, but also provide the search form (see layout.liquid) on the page too, allowing the user to search for the required content.

Partials

As with Rails if we have content that we will use on more than one Liquid template, we can store it in a partical and include it in the templates where needed, for example our tag, archive and search, all list our article listing in the same way. In this case, rather than repeat ourselves for each file we could include the heading in each of the tag, archive and search files and for the actual listing place the code that is repeated in a file called _articles.liquid, i.e.

  1. {{ article | link_to_article }}
  2. {{ article.published_at | date: ‘%b %d’ }}
  3. {{ article.author.login }}
  4. {{ article | linked_tag_list }}
  5. <a href={{ article.url }}#comments>{{ article.comments_count | pluralize: ‘comment’ }}</a>

and then in tag.liquid, archive.liquid and search.liquid include this file for each article in our articles object as follows:

  1. {% include ‘article’ with articles %}

Distributing Templates

Finally if we want to distribute our templates, or if you think you have a good template, why not upload it to the Mephisto Theme Gallery . To do this we need to package the contents of our theme direcory into a .zip file, but before we do this, we need to firstly create a preview image of our theme called preview.png in the root of our theme directory and also create a descriptor file that includes who you are, what the theme is called etc. This is stored in a file called about.yml and is defined in YAML as follows:

  1. title: ClockObj Theme
  2. author: Jon Milet Baker
  3. version: 1.0
  4. homepage: http://www.gotripod.com
  5. summary: THe theme for www.gotripod.com

This article has hopefully been a useful overview to creating your own Mephisto theme. There are lots of resources not only on Mephisto’s site but also on their Wiki

More Information



12 comments below:


Thanks so much! This is exactly what I’ve needed at the right moment! Wow, do share more. For example, I’m also interested in print, pdf and perhaps other types of output (using REST?).

Comment by ylon — 2 November 2007 @ 00:12

ROR?

Comment by Zerga — 2 November 2007 @ 00:13

ROR = Ruby on Rails – Sorry for the acronym ;)

Comment by Jon — 2 November 2007 @ 00:13

This is what I was looking for. I was reading thru the article a few times and i hope I can jump in to the creation of a new theme for which I already have the design, I ‘just’ need to implement it with the things above. Probably I will come back to ask some questions regarding to this project of mine, if I can :)
Thanks a lot!!

Comment by dan — 2 November 2007 @ 18:11

Fabulous resource. Thanks for putting this all down. I’ve tried to customize a few Mephisto templates and was a little frustrated by the absence of something like this.

Comment by Luke Harmtan — 19 November 2007 @ 00:06

good article but there are several mistakes:
1. ‘%’ missing, like this {% for month in section.months }
2. Archives implementation is wrong, you when you click on the archive link and go to the archive page and then you will find the archive link will be wrong.
you should implement is like this:
{% for month in section.months %}
{{ section | monthly_articles: month | size | assign_to: ‘articles_count’ }}
{% if articles_count > 0 %}

{{section | link_to_month: month}} ({{articles_count}})

{% endif %}
{% endfor %}

use the {{section | link_to_month: month}} to generate the link

Comment by Leondu — 21 November 2007 @ 16:15

Thanks for the corrections, You are correct coderay unfortunately did not like the liquid formatting and seems to have dropped certain % signs. Thanks for pointing out and fixing the issue with th archive link snippet.

Comment by Jon — 21 November 2007 @ 19:25

[...] creating a liquid mephisto theme blog entry [...]

Pingback by yannicks investlog » Blog Archive » liquid templates for rails — 6 January 2008 @ 18:27

Jackson Pires has translated this article into Brazilian Portuguese here:
http://jacksonpires.blogspot.com/2008/02/criando-um-tema-para-o-mephisto.html

Thanks, Jon

Comment by Jon — 7 February 2008 @ 13:44

Nice article, thank you. Please tell also how to use articles tags in meta keywords?

Comment by Dmitry — 21 April 2008 @ 11:01

i translate this article to russian – http://fakmak.com/2008/4/21/meqhisto-liquid

Comment by Dmitry — 21 April 2008 @ 15:55

may be this article can help you more http://www.railshacks.com/mephisto-theme

Comment by shunya — 13 June 2008 @ 15:46

Leave a comment

About Jon

Jon started his career hacking code on his Sinclair Spectrum before moving on to more sophisticated machines ( ...such as a Commodore 64 ). He graduated from the University of Kent in 2000 with a degree in Computer Science and since then has worked in finance and education before co-founding Go Tripod. He is passionate about usability and design and his favourite development technologies are Ruby, and Objective-C/Cocoa. When he is not sat at his desk he is standing on his head doing yoga, refining his taste for food or on an adventure exploring the great outdoors.

Go Tripod Ltd

Go Tripod Ltd is a UK-based development company working with some of the most exciting software technologies around. Simon Ashley, Jon Baker and Colin Ramsay are the brains behind projects such as Stubmatic, and are developing bespoke web, mobile and desktop software for clients with household names. We believe in good service as well as good software, and we’re eager to work with people who feel the same.