Adding Blog Tags using Webby

Posted on April 06, 2009

The blog now looks better and better, but it is still missing a key feature — tags.

Let’s bust it out! Here is my plan:

  • Adding a tags attribute under each blog’s meta data
  • Make a helper that reads each blog and count the occurance of each tag
  • Make a partial that links to each tags
  • Make a rake task that auto generates tags folder

Adding a tags attribute under each blog’s meta data

This is easy, just open up a post and add a tags attribute to the meta data:

title         :   Adding Blog Tags using Webby
created_at    :   2009-04-06 19:12:00.343030 +08:00
blog_post     :   true
filter:
  - erb
  - textile
# Add some tags for this post
tags:
  - ruby
  - webby

Make tags helper

All I need to do is to make a tags helper module that does the counting for me, and register it with Webby. Here is the code:

# lib/tags_helper.rbS
module TagsHelper

  # find all blog posts
  def posts(limit=:all, find_options=nil)
    options = { :in_directory => 'articles', 
                :recursive => true,
                :blog_post => true,
                :sort_by => "created_at",
                :reverse => true}
    options.merge!(find_options) if find_options
    ::Webby::Resources.pages.find(limit, options)
  end
  
  def tags_hash
    return @tags_hash if @tags_hash
    @tags_hash = {}
    posts.each do |post|
      post.tags.each do |tag|
        @tags_hash[tag] ||=0
        @tags_hash[tag] += 1
      end if post.tags
    end
    @tags_hash
  end
  
  def posts_with_tag(tag, limit=:all, find_options=nil)
    posts(limit, find_options) do |post|
      post.tags && post.tags.include?(tag)
    end
  end
end

Webby::Helpers.register(TagsHelper)

posts is a handy little short cut for getting all blog posts, much shorter to type. You can also pass in the limit, and find_options to customize your find. Example:

# finding first 10 posts in blogs dir, and sorted in descending chronological order
posts(10, :in_directory => 'blogs', :sort_by => "created_at", :reverse => true)

tags_hash returns a hash with tag name and occurance as the key and value.

posts_with_tag finds all the blog posts related to a tag.

Make a partial

Now that we have the helper, we can make a partial that displays the tags. I made it in HAML:

%ul
  / sort tags in alphabetical order, and then generate links for each tag
  -tags_hash.keys.sort.each do |tag|
    %li
      %a{:href=>"/tags/#{tag}"}= tag
      ==(#{tags_hash[tag]})

You can see the partial in effect on the lower right side of the page in footer. This is basic and nothing fancy…

Make a Rake Task

Now the tags are in place, we want actually display the tags pages. We make a new rake task to generate all the tags page for us.

#tags.rake

require 'lib/tags.rb'
include TagsHelper
namespace :tags do
  desc "auto generate all tags page"
  task :generate do
    ::Webby.load_files
    tags_hash.keys.each do |tag|
      dir = Webby.site.tags_dir
      page = File.join(dir, File.basename(tag))
      page = Webby::Builder.create(page, :from => "#{Webby.site.template_dir}/tags/generate.erb",
                 :locals => {:tag => tag, :directory => dir})
    end
  end
  
  desc "remove all tags page"
  task :remove do
    rm_r Webby.site.content_dir + "/" + Webby.site.tags_dir
  end
  
  desc "regenerate all tags page"
  task :regenerate => [:remove, :generate]
end

You will also need the corresponding templates/tags/generate.erb, which you can find in my github account