Add tags to your Hakyll blog
As promised, here is a simple tutorial about adding tag supports to your Hakyll blog.
Few things before we start:
My Hakyll version used for this article is
188.8.131.52, other versions shouldn't have much difference.
If this article looks too verbose, you can just look at bold sentences.
All the changes done below is contained in this archive. You can download, run it and skip rest of this article.
Let's start from scratch to keep it as simple as possible.
So we initialize a new Hakyll website.
# initialize the website under dir `mondo` $ hakyll-init mondo $ cd mondo # compile the code necessary, # in order to see the website. $ ghc site
Write tags in posts
To create tags, we should first learn how to add tags to our posts, this step is easy, look at the document for tags, it should begin with
tags: followed with a comma-separated list.
Now, let's modify posts from
--- title: S.P.Q.R. tags: foo, bar1, bar2 ---
--- title: Rosa Rosa Rosam author: Ovidius tags: bar1 ---
--- title: Carpe Diem tags: bar2, foo ---
--- title: Tu Quoque author: Julius tags: bar1, bar2 ---
Fetch metadata from our posts
Now we've assigned tags to the posts, next thing is to make them accessible from Haskell codes.
Before we go through all the posts and generate pages, we should build tags using
Unforuntately this function is not well-documented, a short explanation would be :
buildTags pattern makeId finds all tags from posts captured by
pattern, converts each tag to a corresponding
Identifier by using
makeId and returns a value of type
site.hs file, find these lines:
24 25 26 27 28 29
Insert the following code in front of it:
-- build up tags tags <- buildTags "posts/*" (fromCapture "tags/*.html")
The code region above says: find all tags by searching the metadata of posts found by pattern
posts/*, and the corresponding path for each tag will be of form
tags/*.html. (e.g. for tag
foo, you can generate a list of all posts that contains tag
foo under URL:
After tags are generated, we need to tell the post generator to include the corresponding tag informations for each tag, this is done by modifying
postCtx. (for now you don't have to understand the detail of
postCtx if you just want to setup up tags.)
Put the following definition somewhere in your
site.hs, I choose to put it right after the definition of
postCtxWithTags :: Tags -> Context String postCtxWithTags tags = tagsField "tags" tags `mappend` postCtx
And then change all the occurrence of
postCtx inside the code region mentioned above.
After this change, the code region should look like:
24 25 26 27 28 29 30 31 32
Now we need to add some changes to our templates, to make tags visible.
I think the following changes in this section are self-explanatory even if you knows nothing about how template works. So Let's go though them quickly.
templates/post.html to make it looks like:
<div class="info"> Posted on $date$ $if(author)$ by $author$ $endif$ </div> <div class="info"> $if(tags)$ Tags: $tags$ $endif$ </div> $body$
Now we create the template for tag pages which lists all posts containing the corresponding tags. Since we already have a template for listing posts(
template/post-list.html), we can simply reuse it.
This is done by creating a new file:
templates/tag.html, with the following content:
Generate tag pages
This is the final step, we generate tag pages based on the templates we've written.
Put the following code somewhere after we build up
tags, I choose to place it right after the line
tags <- buildTags:
tagsRules tags $ \tag pattern -> do let title = "Posts tagged \"" ++ tag ++ "\"" route idRoute compile $ do posts <- recentFirst =<< loadAll pattern let ctx = constField "title" title `mappend` listField "posts" postCtx (return posts) `mappend` defaultContext makeItem "" >>= loadAndApplyTemplate "templates/tag.html" ctx >>= loadAndApplyTemplate "templates/default.html" ctx >>= relativizeUrls
Now it's done, recompile
site.hs and have fun!
Few screenshots after we adding tags:
I also provide the final version of
mondo directory here.