Building a blog with Nanoc

26 September 2011

This blog is built using Nanoc. Nanoc is a comprehensive tool for making static websites. It is written in Ruby and has a lot of flexibility. I used Howto build a blog with nanoc to get started with my blog. However this article is a few years old now and some of the instructions didn’t work for me. So here is my tutorial on building a blog with Nanoc.

Notes:

  • I am using nanoc version 3.1.9.
  • Nanoc provides a command line tool for creating new items (pages, stylesheets etc) and layouts. I don’t use them, I just make the file using my editor (vim).

Getting Started

Install nanoc and create a site:

gem install nanoc
nanoc create_site my_blog
cd my_blog

Have a look at the file structure that nanoc has created. The most important directories are content which defines all the items for your site (pages, stylesheets etc) and layout which has templates that are shared across items. Start nanoc auto-compile server: nanoc aco & and point your browser to http://localhost:3000/. You should see the default nanoc welcome screen.

Making our first blog post

We’ll make a new file content/blog/first_post.md which will contain our post content and meta data

mkdir content/blog

content/blog/first_post.md

---
kind: article
created_at: 1 January 1970
title: First Post
---
Hello World!

All blog posts should have kind: article and created_at: <timestamp>. The timestamp can be any text that is parseable by Time.parse. This meta data is used later on when we make an landing page for our blog.

Go to http://localhost:3000/blog/first_post/index.html. You should see your post with the default nanoc layout. The layout is specified in layout/default.html, you should modify this file to suit.

Adding post meta data

To show your post title and date you need to include some ruby code just above <%= yield %> in the default layout:

layout/default.html

 ...
 <h1><%= link_to(@item[:title], @item.path) %></h1>
 <p class="created_at"><%= @item[:created_at] %></p>
 <%= yield %>
 ...

For link_to to work we need to load an extra nanoc helper:

lib/helper.rb

include Nanoc3::Helpers::LinkTo

Reload the page in your browser. You should see the title and date included in your post.

Making a landing page for your blog

To make the landing page for the blog we are going to need to use some more advanced features of Nanoc. First of all we will want to share the common layout between the landing page and the individual posts. To do this make a new layout that is specific to posts:

layout/post.html.erb

 <h1><%= link_to(@item[:title], @item.path) %></h1>
 <p class="created_at"><%= @item[:created_at] %></p>
 <%= yield %>

Remove the post specific code from layout/default.html and modify the Rules file so that posts use this new layout.

Rules

...
compile '/blog/*/' do
  layout 'post'
  layout 'default'
end

compile '*' do
...

It is vital that that compile '/blog/*/' do is placed before compile '*' do as Nanoc only uses the first compile rule that matches an item. Check that you post is still rendering correctly.

Next we will need to load the blogging helper and use the sorted_articles method to render links to the articles sorted by created_at date.

lib/helper.rb

...
include Nanoc3::Helpers::Blogging

content/blog.html.erb

<% (@site.sorted_articles[0..4]).each do |post| %>
  <%= link_to(post[:title], post.path) %>
  <%= post[:created_at] %> 
<% end %>

Go to http://localhost:3000/blog/index.html. You should the title and date of your post. Click the title link should take you to the body of the post.

Show the latest article in full on landing page

Lets improve this page to show the first article in full. We need to have access to the body of the first post, without the default layout. We can get this by modifying the blog post compile rule to take a snapshot:

Rules

...
compile '/blog/*/' do
  layout 'post'
  snapshot :body
  layout 'default'
end
...

content/blog.html.erb

<%= articles = @site.sorted_articles %>
<%= articles.first.compiled_content(:snapshot => :body) %>
<% (articles[1..4] || []).each do |post| %>
  <%= link_to(post[:title], post.path) %>
  <%= post[:created_at] %> 
<% end %>

The :body snapshot is the content of the post after the ‘post’ layout has been applied. We render this snapshot in content/blog.html.erb

Add a feed

content/blog/feed.erb

<%= atom_feed :title => 'Nanoc test blog', :author_name => '<your name>', 
              :author_uri => '<your home page>', :limit => 10 %>

atom_feed relies on the base_url configuration paramter which is set in config.yml:

config.yml

base_url: '<your site uri>'
...

Lastly we need compile and routing rules for the feed. Again the order is important, ensure compile 'blog/feed' do is before compile 'blog/*/' do

Rules

...
compile 'blog/feed' do
  filter :erb
end

route 'blog/feed' do
  '/blog/feed.xml'
end

compile 'blog/*/' do
...

Conclusion

In conclusion we have made an awesome blog.

However if you are not yet entirely satisfied can I recommend that you:

Go nuts.