~ 4 min read
Porting a Wordpress blog to Jekyll: Part 2
In the second of my posts in porting a wordpress blog over to jekyll, I outline how I’ve replicated wordpress’s default permalink structure on my own blog.
Creating Category and Tag Pages
Jekyll doesn’t create category or tag index pages for those categories listed in your _posts source. Instead, you’ll need to use a plugin to recreate them. I used the tutorial here as the basis for my category/tag generator, with my plugins/generate_cats_and_tags.rb source below:
module Jekyll
class CatsAndTags < Generator
def generate(site)
site.categories.each do |category|
build_subpages(site, "category", category)
end
site.tags.each do |tag|
build_subpages(site, "tag", tag)
end
end
# Do the actual generation.
def build_subpages(site, type, posts)
posts[1] = posts[1].sort_by { |p| -p.date.to_f }
atomize(site, type, posts)
paginate(site, type, posts)
end
def atomize(site, type, posts)
path = "/#{type}/#{posts[0]}"
atom = AtomPage.new(site, site.source, path, type, posts[0], posts[1])
site.pages << atom
end
def paginate(site, type, posts)
pages = Pager.calculate_pages(posts[1], site.config['paginate'].to_i)
(1..pages).each do |num_page|
pager = Pager.new(site, num_page, posts[1], pages)
slug = posts[0].gsub(' ', '-')
base_path = "/#{type}/#{slug}"
path = base_path
if num_page > 1
path += "/page/#{num_page}"
end
newpage = GroupSubPage.new(site, site.source, path, base_path, type, posts[0])
newpage.pager = pager
site.pages << newpage
end
end
end
class GroupSubPage < Page
def initialize(site, base, dir, base_path, type, val)
@site = site
@base = base
@dir = dir
@name = 'index.html'
self.process(@name)
self.read_yaml(File.join(base, '_layouts'), "group_index.html")
self.data[type] = val
self.data['base'] = base_path
end
end
class AtomPage < Page
def initialize(site, base, dir, type, val, posts)
@site = site
@base = base
@dir = dir
@name = 'atom.xml'
self.process(@name)
self.read_yaml(File.join(base, '_layouts'), "group_atom.xml")
self.data[type] = val
self.data["grouptype"] = type
self.data["posts"] = posts[0..9]
end
end
end
I chose to pass in an extra parameter to the Pager, defining the “base_path” for which an index page has been generated. This enables absolute links to pages and prevents situations like /category/javascript/category/javascript/page/1, which occur when relative pagination is generated when on a category page.
A view making use of it would look like the following:
<div class="pagination">
{% if paginator.previous_page %}
<a href="{{ page.base }}/page/{{ paginator.previous_page }}" class="previous">Previous</a>
{% else %}
<span class="previous">Previous</span>
{% endif %}
<span class="page_number ">Page: {{ paginator.page }} of {{ paginator.total_pages }}</span>
{% if paginator.next_page %}
<a href="{{ page.base }}/page/{{ paginator.next_page }}" class="next">Next</a>
{% else %}
<span class="next ">Next</span>
{% endif %}
</div>
Creating Archive Pages
In a similar fashion, Jekyll doesn’t create pages or pagination for previous years or months. Even if they are not oft used by others, I find it useful myself to hit up my archives for previous years on occasion and laugh at the random work I did for my undergraduate.
I created the following plugin to generate indexes at /{year} /{year}/{month} and /{year}/page/{pageNo} and /{year}/{month}/page/{pageNo} if necessary.
module Jekyll
class ArchiveGenerator < Generator
safe true
def generate(site)
if site.layouts.key? 'archive_index'
site.posts.group_by{ |c| {"month" => c.date.month, "year" => c.date.year} }.each do |period, posts|
posts = posts.sort_by { |p| -p.date.to_f }
archive_dir = File.join(period["year"].to_s(), "%02d" % period["month"].to_s())
paginate(site, archive_dir, posts)
end
site.posts.group_by{ |c| {"year" => c.date.year} }.each do |period, posts|
posts = posts.sort_by { |p| -p.date.to_f }
archive_dir = period["year"].to_s()
paginate(site, archive_dir, posts)
end
end
end
def paginate(site, dir, posts)
pages = Pager.calculate_pages(posts, site.config['paginate'].to_i)
(1..pages).each do |num_page|
pager = Pager.new(site, num_page, posts, pages)
archive_path = "/" + dir
path = archive_path
if num_page > 1
path += "/page/#{num_page}"
end
newpage = ArchiveIndex.new(site, site.source, path, archive_path, posts)
newpage.pager = pager
site.pages << newpage
end
end
end
class ArchiveIndex < Page
def initialize(site, base, dir, base_path, posts)
@site = site
@base = base
@dir = dir
@name = 'index.html'
self.process(@name)
self.read_yaml(File.join(base, '_layouts'), 'archive_index.html')
self.data['base'] = base_path
end
end
end
The layout of the paginator for the archives is the same as that for categories and tags.
That’s it for my jekyll roundup, I other long time wordpress users find this information useful.