I decided to drop tags and categories during the migration form WordPress to Jekyll but as it turned out, it was not the best decision.
I decided to use topics to organize entries as it feels just right because I can quickly separate group of entries and automatically provide RSS feed.
I will shortly describe how I am using mentioned earlier post parameter because it is fairly easy to achieve and modify as you are limited only by your imagination.
How to define one or more topics inside the blog post?
Use topics key to list topics.
--- layout: post title: Jekyll - How to use custom taxonomy or post parameters topics: - Jekyll - Plugins --- <p>contents</p>
The origin
I will use generator code available at the Jekyll's plugins page and just modify it slightly each time to display topics, list posts, and create RSS feed.
module Jekyll class CategoryPage < Page def initialize(site, base, dir, category) @site = site @base = base @dir = dir @name = 'index.html' self.process(@name) self.read_yaml(File.join(base, '_layouts'), 'category_index.html') self.data['category'] = category category_title_prefix = site.config['category_title_prefix'] || 'Category: ' self.data['title'] = "#{category_title_prefix}#{category}" end end class CategoryPageGenerator < Generator safe true def generate(site) if site.layouts.key? 'category_index' dir = site.config['category_dir'] || 'categories' site.categories.keys.each do |category| site.pages << CategoryPage.new(site, site.source, File.join(dir, category), category) end end end end end
List of the topics
To create list of the topics (/topics/index.html file) look at the following plugin source code which uses topic_list.html layout.
module Jekyll class TopicList < Page def initialize(site, base, dir, topics) @site = site @base = base @dir = dir @name = 'index.html' self.process(@name) self.read_yaml(File.join(base, '_layouts'), 'topic_list.html') self.data['topics'] = topics self.data['title'] = "Topics" end end class TopicListGenerator < Generator safe true def generate(site) if site.layouts.key? 'topic_list' dir = 'topics' # get list of the unique topics topics = []; site.posts.each do |p| p.data['topics'].each do |t| topics << t if !topics.include? t end if p.data['topics'] end write_topic_list(site, dir, topics) end end def write_topic_list(site, dir, topics) index = TopicList.new(site, site.source, dir, topics) index.render(site.layouts, site.site_payload) index.write(site.dest) site.pages << index end end end
Notice that generate function inside TopicListGenerator class use topics array to pass further the list of the unique topics.
Use page.topics inside topic_list.html layout to access above-mentioned topic list.
--- layout: index --- {% for topic in page.topics %} <div class="topic"> <h2> <a href="/topic/{{ topic | downcase }}/">{{ topic }}</a> </h2> <div> <small> <a href="/topic/{{ topic | downcase }}/atom.xml">RSS</a> </small> </div> </div> {% endfor %}
Index pages
To create index pages for each topic (/topic/jekyll/index.html file and so on) containing only selected posts look at the following plugin.
Notice that we pass further the topic and posts belonging to this topic.
class TopicIndex < Page def initialize(site, base, dir, topic) @site = site @base = base @dir = dir @name = 'index.html' # get topic's posts topic_posts = [] site.posts.each do |p| ((topic_posts << p) if p.data['topics'].include? topic) if p.data['topics'] end self.process(@name) self.read_yaml(File.join(base, '_layouts'), 'topic_index.html') self.data['posts'] = topic_posts.reverse self.data['topic'] = topic self.data['title'] = "Topic \""+topic+"\"" end end class TopicIndexGenerator < Generator safe true def generate(site) if site.layouts.key? 'topic_index' dir = 'topic' # get list of the unique topics topics = []; site.posts.each do |p| p.data['topics'].each do |t| topics << t if !topics.include? t end if p.data['topics'] end # create page for each topic topics.each do |topic| write_topic_index(site, File.join(dir, topic.downcase), topic) end end end def write_topic_index(site, dir, topic) index = TopicIndex.new(site, site.source, dir, topic) index.render(site.layouts, site.site_payload) index.write(site.dest) site.pages << index end end end
topic_index.html layout doesn't contain anything new.
--- layout: index --- <h1 class="page-title">{{page.title}}</h1> {% for post in page.posts %} {% include content-on-the-list.html %} {% endfor %}
Atom feeds
It is almost identical as above plugin as I just changed names and layout (/topic/jekyll/atom.xml file and so on).
class TopicAtom < Page def initialize(site, base, dir, topic) @site = site @base = base @dir = dir @name = 'atom.xml' # get topic's posts topic_posts = [] site.posts.each do |p| ((topic_posts << p) if p.data['topics'].include? topic) if p.data['topics'] end self.process(@name) self.read_yaml(File.join(base, '_layouts'), 'topic_atom.xml') self.data['posts'] = topic_posts.reverse self.data['topic'] = topic self.data['title'] = "Topic \""+topic+"\"" end end class TopicAtomGenerator < Generator safe true def generate(site) if site.layouts.key? 'topic_atom' dir = 'topic' topics = []; # get list of the unique topics site.posts.each do |p| p.data['topics'].each do |t| topics << t if !topics.include? t end if p.data['topics'] end # create RSS feed for each topic topics.each do |topic| write_topic_atom(site, File.join(dir, topic.downcase), topic) end end end def write_topic_atom(site, dir, topic) index = TopicAtom.new(site, site.source, dir, topic) index.render(site.layouts, site.site_payload) index.write(site.dest) site.pages << index end end end
topic_atom.xml does not use any other layout as it is just simple Atom feed.
--- layout: nil --- <?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <title>sleeplessbeastie's notes - {{ page.topic }}</title> <link href="{{ site.production_url }}/topic/{{ page.topic | downcase }}/atom.xml" rel="self" /> <link href="{{ site.production_url }}/topic/{{ page.topic | downcase }}/" /> <updated>{{ page.posts.first.date | date_to_xmlschema }}</updated> <id>{{ site.production_url }}/</id> <author> <name>Milosz Galazka</name> </author> {% for post in page.posts offset: 0 limit: 10 %} <entry> <title>{{ post.title }}</title> <link href="{{ site.production_url }}{{ post.url }}/" /> <updated>{{ post.date | date_to_xmlschema }}</updated> <id>{{ site.production_url }}{{ post.url }}/</id> <content type="html">{{ post.content | postmorefilter: post.url | xml_escape }}</content> </entry> {% endfor %} </feed>