Planet Jekyll

the unofficial alterslash-style digest


  1. Build Your Navigation Menu Using _data/nav.yml Jekyll Snippets (Tips 'n' Tricks) • over a year ago
  2. Reading Time (e.g. 3 mins) with _includes/reading_time.html Template Jekyll Snippets (Tips 'n' Tricks) • over a year ago
  3. Incremental regeneration in latest jekyll build Tuan Anh Tran @ Bangkok › Thailand • over a year ago
  4. Reinventing the table of contents Tom Johnson (I'd Rather Be Writing) @ San Jose, CA › United States • over a year ago
  5. Jekyll 3.0.0.beta1 Released Official Jekyll News • over a year ago
  6. Language-Agnostic Interfaces for Software Development Parker Moore @ San Francisco, CA › United States • over a year ago
  7. Jekyll Meet & Greet at GitHub HQ Official Jekyll News • over a year ago
  8. Create a contact form with jekyll Tuan Anh Tran @ Bangkok › Thailand • over a year ago
  9. Jekyll: Reading time without plugins Carlos Alexandro Becker @ Joinville, SC › Brazil • over a year ago
  10. So I upgraded my VPS Tuan Anh Tran @ Bangkok › Thailand • over a year ago
  11. Octopress 3.0 is coming Offical Octopress News • over a year ago
  12. Experimenting with Jekyll for tech comm Tom Johnson (I'd Rather Be Writing) @ San Jose, CA › United States • over a year ago
  13. Using AngularJS with jekyll Tuan Anh Tran @ Bangkok › Thailand • over a year ago
  14. Jekyll with Sass Carlos Alexandro Becker @ Joinville, SC › Brazil • over a year ago
  15. Ruby 2.2.0 Time#parse TZ-related regression Parker Moore @ San Francisco, CA › United States • over a year ago

Build Your Navigation Menu Using _data/nav.yml

Jekyll Snippets (Tips 'n' Tricks) Saturday February 07, 2015 @ 00:00 • over a year ago

Build Your Navigation Menu Using _data/nav.yml

In your _data folder add a new navigation file. Example:


- title: "Home"
  href: "/"

- title: "News"
  href: "/news/"

- title: "Snippets"
    - subtitle: "Example1"
      subhref: "#"
    - subtitle: "Example2"
      subhref: "#"


    {% for nav in %}
      {% if nav.subcategories != null %}
          <a href="{{ site.url }}{{ nav.url }}">{{ nav.title }} ▼</a>
          {% for subcategory in nav.subcategories %}
            <li><a href="{{ site.url }}{{ subcategory.subhref }}">{{ subcategory.subtitle }}</a></li>
          {% endfor %}
      {% elsif nav.title == page.title %}
         <li class="active">
           <a href="{{ nav.url }}">{{ nav.title }}</a>
      {% else %} 
          <a href="{{ site.url }}{{ nav.href }}">{{ nav.title }}</a>
      {% endif %}
    {% endfor %}

Note: U+25BC (&#x25BC;) is the unicode for a black down-pointing triange (e.g. )


Reading Time (e.g. 3 mins) with _includes/reading_time.html Template

To add the reading time (e.g. 3 mins) to your posts include the reading_time.html template in your post layout. Example:

{% include reading_time.html %}


<span class="reading-time" title="Estimated read time">
  {% assign words = content | number_of_words %}
  {% if words < 360 %}
    1 min
  {% else %}
    {{ words | divided_by:180 }} mins
  {% endif %}

Note: The template assumes a reading speed of 180 words per minute (WPM).


Incremental regeneration in latest jekyll build

Tuan Anh Tran @ Bangkok › Thailand Saturday January 31, 2015 @ 05:00 • over a year ago

jekyll is an awesome static generator but its regenetion time is totally unexceptable. It works well when you have small number of posts but start to degrade as number of posts increases. Actually, I don’t care about it much when I git push to the repo because my VPS is using SSD-cached but previewing the site at localhost is such a pain.

So when I take a look at jekyll again today and see this pull request, I’m so excited and couldn’t help but clone the repo and rebuild jekyll to test it out myself.

git clone
gem build jekyll.gemspec
gem install jekyll*.gem

A quick look at jekyll reveals that it now has a file named .jekyll-metadata to keep track of mtime of the change file and their dependencies.

  mtime: 2015-01-31 12:31:57.000000000 +07:00
  - /Source/
  - D:/Source/
  - D:/Source/
  - D:/Source/
  - /Source/
  mtime: 2015-01-31 12:31:57.000000000 +07:00
  - /Source/
  - D:/Source/
  - D:/Source/
  - D:/Source/
  - /Source/

I tested the beta gem on an old PC of mine with 5400rpm HDD to see how much speedup the new build offers. Prior this, when using jekyll serve, the regeneration speed is really slow. It takes minutes (literally minuteS) for a site with barely over 100 posts.


It does actually speedup. A quick change in a single file now takes 17 to 40 seconds to regenerate (of total ~100 posts). Still no where near the speed I expect but it’s a big step up from where it was. I’ll take it :)

This pull request is expected to be in jekyll 2.6.0 release.

I’ve been exploring different ways to create a table of contents (TOC). Traditionally, user guides have a long TOC in the left column of each page. This works all right when you have about 50 pages, but when you scale up the doc set to 500 pages, the TOC becomes a bulky, unusable mess. For Continue Reading »

Jekyll 3.0.0.beta1 Released

Official Jekyll News Saturday January 24, 2015 @ 08:42 • over a year ago


Exciting news! First beta for Jekyll 3 is out. Check out the sizable changelog to get a feel for what changes are afoot. Key features:

  1. Speed. Jekyll now features incremental regeneration and greatly improved problematic code that caused slow-downs.
  2. Gobs of bugfixes and customization.
  3. Uniformity and sanity to Jekyll extensions of Liquid.

To install just run:

$ gem install jekyll --pre

Future versions will include some awesome new features that we haven’t built yet. If you see one you want to tackle, submit a PR & you’ll be featured in the Jekyll 3.0 release post as a contributor to that epic release.

Please file bugs as you encounter them, being sure to include your version of Ruby, the Jekyll version, and (if possible) a link to your site so we can reproduce.

If you think there’s room for improvement in the UX, also do let us know. We’re always looking to make Jekyll easier to use!

Happy Jekylling!

Don’t let the title fool you, the concept here is simple: provide simple scripts in your repositories so – no matter the language or tools used – a newcomer to the code base can get started quickly and easily.

This is an idea I picked up from GitHub – they use it heavily throughout the company and in their open source projects. I have expanded on this a bit and proposed it to my colleagues at VSCO. With some tweaking, we now have the following in almost all our projects my team works on:

  1. script/bootstrap
  2. script/build
  3. script/test
  4. script/cibuild
  5. script/server

First, script/bootstrap installs dependencies and gets your project ready for development. In a Ruby project, this would be bundle install. In a Go project, this might be a series of go get calls.

Next, script/build builds your project. This ranges depending upon the project. For a mobile app, it would be the compile & build step. For a website, it might be the minification step for your assets. If you’re running Jekyll, this would be equivalent to jekyll build.

Then you have script/test. This runs your test suite, whatever it may be. Notably, this step does not include setting up for tests, unless it’s required for every single test run. Usually it’s just a call to rspec, mocha, or what have you.

Naturally, script/cibuild follows. It’s used to setup and execute all tests. This could be seeding a database, running a linter, whatever. It should only pass if the code is production-ready.

Last, we have script/server. My team works primarily on server technology, so this is of crucial importance to us. This allows one to run the server for development purposes. It’s usually not used in production, but could easily be incorporated if another server (e.g. nginx or apache) weren’t being used.

These scripts have saved us a lot of frustration, and a lot of time fighting with package managers, test suites, etc. The best part is that when you clone a repo, you know immediately how to get started, regardless of the language.

I have put these in most of my actively-maintained open source repos that require these steps, projects like Jekyll (and its components), as well as some Golang servers I have built including gossip and ping.

We see the power of common, language-agnostic interfaces all the time. Automating the installation from source of many packages is as simple as wget, tar, ./configure, make, make install. It’s not super easy the first time, but once you learn it, you have access to hundreds of utilities that haven’t been added to your package manager for one reason or another.

Language-agnostic interface scripts like what I describe above are all about making it easier – reducing friction – to develop and iterate on software. Try it out in your projects and see how much time and frustration you can save just by hiding project-level complexity.

Jekyll Meet & Greet at GitHub HQ

Official Jekyll News Wednesday January 21, 2015 @ 03:23 • over a year ago

Hey! Our friends at GitHub have agreed to host a Jekyll meet & greet on February 5, 2015 at 7pm. The event will be hosted at GitHub’s Headquarters here in San Francisco, CA. Pizza & beer will be available for those interested, and there will be much time to sit and chat about all things Jekyll. This would be an especially good time to get help with bugs you’ve encountered or to talk over a potential feature with the core team in attendance.

A special thanks to @gjtorikian for making this all possible! You rock.

We look forward to meeting all you fine folks. Cheers!

Create a contact form with jekyll

Tuan Anh Tran @ Bangkok › Thailand Tuesday January 20, 2015 @ 05:00 • over a year ago

Since jekyll blog is static, we have to rely some some kind of service endpoint to send email to our mailbox. Good thing is that there are plenty of services for this purpose: heroku for free hosting and mailgun, mandrill or mailjet for sending email. Pick one of your choice.

I did a quick search before firing up Sublime Text to create a simple app for sending email and luckily, someone already wrote one. One less thing to do :)

Create Heroku and a Mandrill account

Sign up an account at Heroku. Download and install heroku toolbelt while you’re at it.

For sending email, you can go with Mandrill, Mailgun or Mailjet. They all come with free plan which is more than enough for personal use. If you pick something other than Mandrill, you will have to edit the app a bit use their own libraries. If you’re lazy, just go with Mandrill.

Install the app on heroku

heroku auth:login # enter your account credentials when askedgit clone
heroku create <YOUR_HEROKU_APP>
heroku config:set MANDRILL_API_KEY=<KEY>
heroku config:set USER_EMAIL=<YOUR EMAIL>
heroku config:set USER_SITE=<YOUR SITE>
heroku config:set SUCCESS_PAGE=<A SUCCESS PAGE TO REDIRECT USER TO AFTER THE MESSAGE IS SENT>git push heroku master # deploy

Create contact form on your website

Create a page with simple form like below. I’m using Bootstrap for my blog so styling is just a matter of adding a couple of CSS classes.

<form action="https://<YOUR_HEROKU_APP>">
  Email: <input type="text" name="name"><br>
  Name: <input type="text" name="email"><br>
  Subject: <input type="text" name="subject"><br>
  Message: <textarea name="message" cols="40" rows="5"></textarea>
  <input type="submit" value="Send Message">

Adding reCAPTCHA (optional)

Sign up for an API key pair and add it to your page. I don’t have a need for this, personally.

Here what’s mine like

contact form with jekyll

Jekyll: Reading time without plugins

Carlos Alexandro Becker @ Joinville, SC › Brazil Monday January 19, 2015 @ 02:00 • over a year ago

Estimated reading time of a post is a feature that became popular, I believe, with Medium.

There are plenty of Jekyll plugins that address this problem, but, if you want to deploy at GitHub Pages, you can't use those plugins (GitHub will run with the --safe flag).

So, I created a snipped of pure Liquid code to fix that.

So, the first thing we will want to do is get the word count. That's pretty, actually:

{% assign words = content | number_of_words %}

Now, we need to divide this number with something. This something is called Word per minute (WPM). According to Wikipedia, an average person can read 180 words per minute in a computer monitor. Now it became really easy to do the rest:

{{ words | divided_by:180 }} mins

But, what if the post has less than 180 words? Actually, even if it has more, 350 words, for instance, when divided by 180, will result in 1.94, Liquid will round it down to 1, so, the user will see "1 mins", which is weird. To fix that, we have to check if it has less than 360 words, because any number great or equal 360 will result in 2+ mins, which still plural.

That said, the solution is quite simple:

{% if words < 360 %}
  1 min
{% else %}
  {{ words | divided_by:180 }} mins
{% endif %}

So, to keep it organized, I put all this in a read_time.html in my _includes folder:

<span class="reading-time" title="Estimated read time">
  {% assign words = content | number_of_words %}
  {% if words < 360 %}
    1 min
  {% else %}
    {{ words | divided_by:180 }} mins
  {% endif %}

And then I just include it in my post layout:

{% include read_time.html %}

And it works, as you can see here. Hope you like! :beers:

So I upgraded my VPS

Tuan Anh Tran @ Bangkok › Thailand Friday January 16, 2015 @ 05:00 • over a year ago

I have little to none demand for web server’s power since my blog is static, plus a couple of small web apps I test on the VPS now and then. Recently, my interests shifted to Ionic framework, nodejs, mongodb and angularjs. I had quite a few ideas for pet projects, mostly for the purpose of learning. I decided to upgrade my VPS to a bit better plan - 256MB of RAM. Still a tiny machine but should be enough for what I have in mind.

I’ve also did a re-installation of the OS as I switch from 64bit Ubuntu 14.04 image to 32bit version. I have no plan to scale this VPS for anything serious so 32bit is good plenty for the purpose, plus all the additional bit of memory.

Migration process is rather painless. I just had to click Re-install OS, setup new user account, apt-get a couple of libs (rvm, ruby, jekyll), setup git server and then git push my blog. Everything is back to normal now I suppose.

Octopress 3.0 is coming

Offical Octopress News Thursday January 15, 2015 @ 19:07 • over a year ago

The way Octopress is being distributed and maintained is nearing its end. There are many things I've always disliked about how Octopress works. So before I talk about the exciting part, I'd like to tell you what's wrong with Octopress.

What's wrong?

If I'm being harsh, I'll tell you that as it is now, Octopress is basically some guy's Jekyll blog you can fork and modify. The first, and most obvious flaw, is that Octopress is distributed through Git. I want to punch through a wall when I think about users wrestling with merge conflicts from updating their sites. It’s absurd.

Octopress is released as a single product, but it's a collection of plugins and configurations which are hard to disentangle. if you want to change or remove anything you're leaving the "golden path" and updates will be painful, if not impossible — short of copy and paste. Even I can't remove things from Octopress. If I want to stop maintaining a plugin it will also disappear for anyone who updates. While some have suggested using Git tags as a kind of steam-punk versioning, that simply will not solve the real problem. This isn't how software products should be distributed. Git is for collaborators; not users.

Then there are the themes. I planned to create a system for distributing themes independently from Octopress, but I hadn’t solved it when I released 2.0. Even then, I've come across quite a few websites with Octopress theme galleries. While there are some nice ones, they are all distributed through git and installed with an ill-conceived rake task that was never meant to be used for this. All of this is a constant reminder that many people are spending time building on my mistakes.

However, the part I dislike the most is the notion that Octopress and Jekyll are different communities. Because Octopress is single product with a theme, plugins, and command line automation, the best I could offer the Jekyll community was a pile of source code. It was effectively a salvage yard of ideas on Jekyll blogging.

I've spent the two and a half years working on the next version of Octopress. Two years ago, Parker Moore joined the team and with his help. I’ve finally built something I’m proud of.

What's coming?

This release is a full rewrite. Octopress as it is now will be replaced by a selection of gems, each semantically versioned with is own documentation and tests. Of the gems I’ve written for this release, some are replacements for plugins that were originally integrated into Octopress and others are completely new. I will be working on a migration guide for current Octopress users, but each plugin can be used on any Jekyll site. There will no longer be a division between Octopress and Jekyll.

Here’s a brief overview of the core components of the new Octopress.

The Octopress CLI replaces the old Rakefile and has some new tricks too. With octopress and the octopress-deploy gem you can:

  • Quickly create new pages, posts, drafts, and collections.
  • Upgrade your drafts workflow with the publish and unpublish commands.
  • Use templates, like: octopress new post --template sponsor.
  • Deploy via Git, Rsync, and S3.
  • View local documentation with the docs command.

That last one is actually pretty neat. Each Octopress gem integrates its documentation with the Octopress CLI so when you run octopress docs from your site, you’ll see the documentation for the exact version of every plugin your site is using. Switch to a different site with different plugins and you’ll see a different docs site. Third-party gem-based plugin can easily integrate their documentation too. I’m even using this documentation system to build the new Octopress website.

Octopress Ink is a framework I’ve built for helping plugin authors rapidly build powerful plugins and themes for Jekyll sites. It has some crazy cool features.

  • Plugins are easily installed and removed; they only affect the build. A user's source is left alone.
  • Use a plugin's layouts, includes, pages and files right from the gem, for example: {% include twitter:feed.html %}.
  • Plugin Javascripts, Stylesheets, images, fonts, etc. are easily integrated.
  • Each plugin’s javascripts and stylesheets are compiled, compressed, and fingerprinted automatically.
  • Users can override or disable any component of a plugin.
  • Each plugin is configured independently at _plugins/plugin_name/config.yml, so no more pollution of Jekyll's _config.yml.
  • Generate a plugin scaffold with octopress ink new <PLUGIN_NAME> and build powerful, gem-based plugins quickly.

In order to remain sane working on all this, I created some new developer tools as well. If you are building Jekyll plugins or even just working with advanced templates, these should be helpful.

Clash is a simple static-site test suite. It can build Jekyll sites with different configurations and it compares output with a simple but powerful diff system.

Octopress Debugger lets you add a Liquid tag {% debug %}, to your sites and interact with the site, page and, scopes instances in an interactive ruby console. This makes it easy to see how variables are set, or even step through a for loop. It’s a cool way to see what Jekyll is doing under the hood as it builds your site.

Finally, I’m working on a new theme. It’s called “Octopress Genesis”, and it will demonstrate many of the features of Octopress Ink and set a pattern for how Jekyll themes should be created. Once that’s finished, I’ll use it for the new docs site and launch this beast.

There’s a lot more — around 30 gems at this point — and if you’re curious, you can browse the Octopress organization on GitHub. Quite a few people have been using these plugins already and their issues and pull-requests have been a great help.

The release plan

For the release, I plan to do the following:

  1. Finish Octopress Genesis
  2. Write a migration guide
  3. Move the master branch to the legacy branch for maintenance releases and modify rake tasks accordingly.
  4. Move imathis/octopress to the Octopress org on GitHub.
  5. Release the new docs site.
  6. Release Octopress as 3.0 and Octopress Ink as 1.0

After the release, I will begin closing out issues and pull requests that can be resolved by replacing old plugins with gems. Anyone who wants to help with that effort will earn a special place in my heart. Working on the “legacy codebase” is very challenging and I intend to avoid anything but critical updates in the future.

Thanks to everyone for your help, encouragement, and patience as I figure out what I’m doing in public. I can’t wait to ship this and I look forward to a bright future with a better Octopress.

— Brandon Mathis

⚓ Permalink

Today I had the opportunity to explore Jekyll a bit more. Jekyll is a static site generator that helps you build websites quickly. The sites can be blog sites or regular sites (or documentation sites). However they’re used, there’s definitely a trend toward static site generators over database-driven sites. Seven years ago, online CMS platforms Continue Reading »

Using AngularJS with jekyll

Tuan Anh Tran @ Bangkok › Thailand Wednesday January 14, 2015 @ 05:00 • over a year ago

This blog is running on jekyll; and since I’m learning AngularJS, I want to try AngularJS on my blog as well. The problem is both are using double curly braces syntax, jekyll will consume it first when generating and AngularJS will be left with nothing.

In order to use AngularJS with jekyll, we have to instruct AngularJS to use different start and end symbol by using $interpolateProvider.

var myApp = angular.module('myApp', [], function($interpolateProvider) {
});function MyCtrl($scope) {
  $ = 'Clark Kent';

Using it with the new symbol

<div ng-controller="MyCtrl">
    Hello, [[name]]

That’s it. Enjoy hacking your blog.

P/S: I didn’t push any change to this blog. I’m just playing AngularJS and jekyll locally

Jekyll with Sass

Carlos Alexandro Becker @ Joinville, SC › Brazil Friday January 09, 2015 @ 02:00 • over a year ago

I followed @mdo recent article "Using Sass with Jekyll", and wanted to point out the results.

I'm using some version of Lanyon with some custom stuff. So, I had 4 CSS files:


Summing it up, ~22K. It's not a lot, but, thinking about mobile 3G plans that are shit (like brazilian ones), why not save some bytes and requests?

So, I moved all those files to a _scss subfolder, and changed their extensions to .scss instead of .css.

Then, in my public/css folder, I created a styles.scss like this one:

# Needed for jekyll...

@import "poole";
@import "syntax";
@import "lanyon";
@import "carlos";

Also, I added the following section to my _config.yml:

  sass_dir: _scss
  style: :compressed

Finally, changed my _includes/head.html to import only the new styles.css:

<link rel="stylesheet" href="/public/css/styles.css">

And boom! It worked. With this, my previously four requests of ~22K went to one request with 12.8K!


Besides that, now I have all the power that Sass provides, in my blog, without any hacks. And it works on GitHub pages!

I was working on adding Ruby 2.2 support to Jekyll, and discovered that the test we have for the timezone option was failing, seemingly inexplicably. After some meandering through the Ruby source code and ChangeLog to determine if the TZ variable was being respected differently, I found no references explicitly to this change. When I walked through how Jekyll uses Time#parse in IRB, I discovered what looks like a pretty major change in 2.2.

In Ruby 2.1, the timezone is converted to the local time (set with the TZ environment variable) automatically:

>> require 'time'
=> true
>> ENV['TZ'] = 'Australia/Melbourne'
=> "Australia/Melbourne"
>> Time.parse("2014-12-29 20:16:32 -0400")
=> 2014-12-30 11:16:32 +1100

But in Ruby 2.2, this was not the case:

>> require 'time'
=> true
>> ENV['TZ'] = 'Australia/Melbourne'
=> "Australia/Melbourne"
>> Time.parse("2014-12-29 20:16:32 -0400")
=> 2014-12-29 20:16:32 -0400 # <== !!! Timezone remains unchanged.
>> Time.parse("2014-12-29 20:16:32 -0400").localtime
=> 2014-12-30 11:16:32 +1100

Go update your gems! Go update your applications! Append #localtime calls anywhere you use Time#parse and want your system timezone respected.


Nobu rejected the above issue I filed, calling this change a bug fix. OK, that seemed weird to me but I could see how this might cause unintended consequences. I asked for a link to the issue that contains the discussion and patches for this change in behaviour. Akira wrote back, saying that there wasn’t one, but that the change was inspired by another bug.

And so ensued the most disheartening experience in my Ruby existence. Issue #9794, the issue Akira referenced, is a bug report filed by a guy named Felipe Contreras. It discusses a discrepancy between Time and DateTime in the #strptime method. While Time.strptime respects timezones when parsing with "%s %z", DateTime.strptime does not. I was looking for a revision which would explain my predicament and ended up reading through the comments, many of which were in Japanese (thanks and no thanks to Google Translate that did very little to help decipher them).

One of the comments referenced Issue #7445, which is basically identical to the #9794. Hmm, weird. It turns out that Felipe filed #7445 about 2 years ago, couldn’t get his point across to Tadayoshi so Tadayoshi just marked it as Rejected and moved on. Felipe, understandably, was frustrated by this. He refiled a year and a half later as #9794 and the argument, again, ensued. It was even discussed over the mailing list. Eventually, after Matz stepped in and called it a ‘feature’, Tadayoshi wrote R45822, a patch for this behaviour. He included an unnecessarily snarky commit message:

a new feature (not a bug fix) of strptime. applies offset even if the given date is not local time (%s and %Q). This is an exceptional feature and I do NOT recommend to use this at all. Thank you git community.

Wow. Tadayoshi was rude, Felipe was rude, and the apparent disinterest in finding a common language was excruciating. Comments flew by one another, Felipe’s in English, others’ in Japanese. Tadayoshi ignored Felipe’s requests to use English. Felipe dismissed Japanese as unacceptable for an “international project”, assuming it must use the Lingua franca of English just because it crosses nation-state borders.

So it seems my problem arose from communication barriers, intense frustration over inconsistency and the apparent lack of ability to see this. And our result: a breaking change between MINOR versions of Ruby, violating SemVer. Ugh.

pluto.models/1.4.0, feed.parser/1.0.0, feed.filter/1.1.1 - Ruby/2.0.0 (2014-11-13/x86_64-linux) on Rails/4.2.0 (production)