Advanced Jekyll Plugins & Features - Custom Post Types, Category Pages, Pagination, and More

Here at Divshot we're huge fans of Jekyll, the static CMS and blogging platform created by the folks at GitHub. We use Jekyll to power everything from our lander, blog, docs and upcoming support pages such as Q&A. It's a fantastic way to keep all of your content under version control and serve it up directly on Amazon S3. In this article I'm going to discuss some of the unique ways we've tweaked Jekyll to create an advanced blog with custom post types, post type pagination, post type filters and more. I'll introduce you to the plugins we use and share a few things I've written along the way.




Custom Post Types in Jekyll

At its core, Jekyll is centered around pages and posts. Posts are blog entries that follow a permalink structure in your config file. You can organize your blog posts by category and date. In an effort to remain a simple blogging platform, going beyond Jekyll's default setup can be an interesting challenge compared to other alternatives such as WordPress. Let's say you want something like posts but you want to have different kinds of posts:

  • Blog Entries
  • Portfolio Items
  • Questions & Answers

There's several ways you could accomplish this task. If you wanted to store your custom posts in a different directory and have the ability to use filenames without dates, you could write your own generator. Going down this path isn't recommended. You'll have to extend and override Jekyll's internal classes to get your custom posts to behave exactly like posts. A much easier way is to use the post permalink and take advantage of categories to build separate directories for your post types. Here's my approach:

1) Edit _config.yml and change your permalink to permalink: /:categories/:title.

2) Create separate subdirectories inside your _posts/ directory to organize your post types, e.g. _posts/blog and _posts/questions.

3) Follow a similar file format for your custom posts. Use a date in the filename. Under categories for each post, specify a custom post type. Do this for every single post in the _posts/ directory based on the post type:

–––
layout: blog
title: Jake's Twitter Bootstrap Blog Post
categories:
– blog
– bootstrap
–––

–––
layout: question
title: What is Divshot?
categories:
– questions
– general
–––

My first category is always the custom post type and my second is the actual category for the post. When Jekyll compiles my site all of my blog posts will go under /blog and my questions will go under /questions. This approach covers the base functionality for custom post types. It's also easy to list all of the posts for a specific post type:

{% for post in site.categories['blog'] %}{% endfor %}

{% for post in site.categories['questions'] %} {% endfor %}

To list out categories for a specific post type we'll need to create a filter.

[top]


Custom Post Type Category List Filter

If we walk through each post via site.categories[post_type] to determine the categories we'll want to remove the post type categories such as blog and questions since they're not actually categories. Create a new Ruby file under _plugins/ and use the following filter:

After you added the filter file, go to the HTML file where you're listing out the categories. Add the following Liquid template tags to loop through the categories:

{% assign blog_categories = site.categories['blog'] | filter_categories_by_primary_category %}
{% for category in blog_categories %}{% endfor %}

We use the {% assign %} tag to create a variable with an array of categories we can print out. That's it! Next I'm going to show you a far more complicated feature that unfortunately doesn't come out of the box in Jekyll: Category pages.

[top]


Category Page Generator with Custom Post Types

Instead of writing my own generator from scratch, I used Dave Perrett's category page generator and tweaked the code to handle my own custom post types. I changed the write_category_index method under the Site class to only select posts with a specific category (my post types) and write the category views to different layout files based on the post type. I'll share an example and let you expand from there:

You'll notice I'm referencing a custom config value from my _config.yml file. I set up a category_dir as mentioned in the category page generator file and another config value for my questions category directory (category_question_dir). This should give you enough code to work out your own solution if you decide to add category pages to your site and want them for your custom post types. One last thing: Similar to how we filtered out our post type categories using RESTRICTED_CATEGORIES under our PostAndCategoryFilter, we'll also want to do the same thing in the category page generator:

[top]


Pagination with Category Pages and Custom Post Types

Although basic blog pagination is built into Jekyll I wanted to write my own generator to handle category pages and custom post types. I attached the entire generator here in full. The paginate method takes a category and will paginate any list of posts. For category pages I wrote a custom paginate_categories method. To loop through these posts in your HTML file you'll want to use the following template tag instead of referencing site.categories[post_type]:

{% for post in paginator.posts %}{% endfor %}

As promised, here's my pagination generator:

[top]


Post Excerpts

Post excerpts allow you to provide a small preview of content before taking the user to the full post. Some plugins limit the excerpt to a certain amount of characters but I prefer specifying the excerpt cut-off with a <!--more--> comment in my post files similar to WordPress. I use the following plugin found in a Gist after looking around:

[top]


Instant Search

Since your Jekyll website is completely static you'll either need to use a JavaScript-based search plugin or embed Google Web Search in your layout. I opted for the former and used an excellent search plugin powered by Lunr. When Jekyll compiles your site, a search.json file is generated with an index of all your posts for instant searching.

[top]


Sitemap Generator

To help Google spider all of our pages (including the category and pagination pages we're generating), I used another generator by Dave Perrett for sitemap generation. You can find all of his plugins available on GitHub.

The nice thing is that you can specify the changefreq and priority page variables directly in the _layouts/ template files without having to add them one-by-one to each custom post.

I tweaked the entry method to only provide a <lastmod> if a last-modified date is available for a specific page. For category and pagination files, the last-modified date is always the Jekyll compilation date since these files are created from scratch. In this case we won't add <lastmod to sitemap.xml.

[top]


Author Support with Rich Snippets

Similar to using a JSON file for search, I'm also using a JSON file to store author metadata to display author info in our blog posts using a Jekyll tag plugin. At compilation time I parse the JSON file with Ruby and render the data in the post.html layout file.

Here's the author tag plugin:

Here's how I add the author metadata to the layout file in a vCard:

[top]


Asset Compilation

Whether it's Sprockets or another asset bundling manager like Grunt or Hem, we absolutely need a way to compile our assets on the fly. That's where Jekyll Assets comes in. All of our CoffeeScript, Sass, and vendor plugins used throughout our Jekyll instances use the jekyll-assets gem to compile everything into a central JavaScript and CSS file. After adding jekyll-assets to your Gemfile, edit your _config.yml like this:

assets:
  sources:
    – _assets/images
    – _assets/javascripts
    – _assets/stylesheets
    – _vendor/stylesheets
    – _vendor/javascripts

When you start your Jekyll server, the assets should be compiled immediately upon file save. If you're only editing a stylesheet, you may want to look into my research on Grunt integration below. It speeds things up dramatically.

[top]


Jekyll on Amazon S3

If you'd like to deploy your Jekyll website to Amazon S3, I recommend the s3_website plugin to get started. Check it out on GitHub.

[top]


Generator Sorting Utility

After creating so many generators of my own, one issue I ran into was specifying the order of generators called when compiling my Jekyll website. My sitemap generator would trigger before my category page generator, so the category pages wouldn't appear in the sitemap.

[top]


Styling Your Jekyll Blog Faster with Grunt

When using a Jekyll assets pipeline such as jekyll-asset or jekyll-asset-pipeline, saving CSS files and waiting for Jekyll to compile can quickly become frustrating when you're using something like LiveReload for live CSS editing.

Fortunately, Thanasis Polychronakis has written a useful Gruntfile for Jekyll and LiveReload to play nicely together. Check it out!

[top]


Wrapping Up

That covers most of the advanced plugins and features we use here at Divshot.

Once you spend some time learning how to create generators, filters, and tags, Jekyll becomes an extremely powerful tool for creating blogs and websites. It may not have the turnkey versatility of WordPress and its plugin ecosystem, but if you want a simple solution that outputs static HTML files then Jekyll is perfect for your needs.