Hyde Press

Simple • Static • Blog-aware

Jekyll Plugins 'n' Tools (Book Edition)

by Ben Balter, Parker Moore, Jordon Bedwell, Sylvester Keil, Gerald Bauer, et al



Note: The book edition is still an early release and a work-in-progess.

This is the plugins and tools documentation (mostly READMEs) for the Jekyll static site builder / generator reformatted in a single-page book edition.

See the source repo for how the book gets auto-built with "plain" Jekyll - of course - and hosted on GitHub Pages.

Questions? Comments? Send them to the Jekyll Talk forum post titled Jekyll Plugins 'n' Tools READMEs Reformatted as a Single Page in Black 'n' White (Book Version).



Thanks to all Jekyll plugin and tool contributors for making it all possible.

Part 1 - Built-in Standard Plugins (Incl. with GitHub Pages)

Chapter 1.1 - Feed

A Jekyll plugin to generate an Atom (RSS-like) feed of your Jekyll posts


Add this line to your site’s Gemfile:

gem 'jekyll-feed'

And then add this line to your site’s _config.yml:

  - jekyll-feed


The plugin will automatically generate an Atom feed at /feed.xml.

Optional configuration options

The plugin will automatically use any of the following configuration variables, if they are present in your site’s _config.yml file.

Already have a feed path?

Do you already have an existing feed someplace other than /feed.xml, but are on a host like GitHub Pages that doesn’t support machine-friendly redirects? If you simply swap out jekyll-feed for your existing template, your existing subscribers won’t continue to get updates. Instead, you can specify a non-default path via your site’s config.

  path: atom.xml

To note, you shouldn’t have to do this unless you already have a feed you’re using, and you can’t or wish not to redirect existing subscribers.

Optional front matter

The plugin will use the following post metadata, automatically generated by Jekyll, which you can override via a post’s YAML front matter:

Additionally, the plugin will use the following values, if present in a post’s YAML front matter:

Meta tags

The plugin exposes a helper tag to expose the appropriate meta tags to support automated discovery of your feed. Simply place {% feed_meta %} someplace in your template’s <head> section, to output the necessary metadata.

Why Atom, and not RSS?

Great question. In short, Atom is a better format. Think of it like RSS 3.0. For more information, see this discussion on why we chose Atom over RSS 2.0.

Chapter 1.2 - Sitemap Generator

Jekyll plugin to silently generate a sitemaps.org compliant sitemap for your Jekyll site


  1. Add gem 'jekyll-sitemap' to your site’s Gemfile and run bundle
  2. Add the following to your site’s _config.yml:
  - jekyll-sitemap

If all gem plugins have the same priority, they will be executed in the order they are required, generally. Thus, if you have other plugins which generate content and store that content in site.pages, site.posts, or site.collections, be sure to require jekyll-sitemap either after those other gems if you want the sitemap to include the generated content, or before those other gems if you don’t want the sitemap to include the generated content from the gems. (Programming is hard.)


If you would like to exclude specific pages/posts from the sitemap set the sitemap flag to false in the front matter for the page/post.

sitemap: false

Developing locally

Use script/bootstrap to bootstrap your local development environment.

Use script/console to load a local IRB console with the Gem.


  1. script/bootstrap
  2. script/cibuild


  1. If the sitemap.xml doesn’t generate in the _site folder, ensure _config.yml doesn’t have safe: true. That prevents all plugins from working.
  2. If the sitemap.xml doesn’t generate in the _site folder, ensure that you don’t have a sitemap generator plugin in your _plugin folder.

Chapter 1.3 - Redirect From

Give your Jekyll posts and pages multiple URLs.

When importing your posts and pages from, say, Tumblr, it’s annoying and impractical to create new pages in the proper subdirectories so they, e.g. /post/123456789/my-slug-that-is-often-incompl, redirect to the new post URL.

Instead of dealing with maintaining those pages for redirection, let jekyll-redirect-from handle it for you.

How it Works

Redirects are performed by serving an HTML file with an HTTP-REFRESH meta tag which points to your destination. No .htaccess file, nginx conf, xml file, or anything else will be generated. It simply creates HTML files.


Add this line to your application’s Gemfile:

gem 'jekyll-redirect-from'

And then execute:

$ bundle

Or install it yourself as:

$ gem install jekyll-redirect-from

Once it’s installed into your evironment, add it to your _config.yml:

  - jekyll-redirect-from

If you’re using Jekyll in safe mode to mimic GitHub Pages, make sure to add jekyll-redirect-from to your whitelist:

  - jekyll-redirect-from

Then run jekyll <cmd> --safe like normal.


The object of this gem is to allow an author to specify multiple URLs for a page, such that the alternative URLs redirect to the new Jekyll URL.

To use it, simply add the array to the YAML front-matter of your page or post:

title: My amazing post
  - /post/123456789/
  - /post/123456789/my-amazing-post/

Redirects including a trailing slash will generate a corresponding subdirectory containing an index.html, while redirects without a trailing slash will generate a corresponding filename without an extension, and without a subdirectory.

For example…

  - /post/123456789/my-amazing-post

…will generate the following page in the destination:



  - /post/123456789/my-amazing-post/

…will generate the following page in the destination:


These pages will contain an HTTP-REFRESH meta tag which redirect to your URL.

You can also specify just one url like this:

title: My other awesome post
redirect_from: /post/123456798/


If site.baseurl is set, its value is used as a prefix for the redirect url automatically. This is useful for scenarios where a site isn’t available from the domain root, so the redirects point to the correct path.

Note: If you are hosting your Jekyll site on GitHub Pages, the prefix is set to the pages domain name i.e. http://example.github.io/project or a custom CNAME.

Redirect To

Sometimes, you may want to redirect a site page to a totally different website. This plugin also supports that with the redirect_to key:

title: My amazing post
  - http://www.github.com

If you have multiple redirect_tos set, only the first one will be respected.

Note: if using redirect_to with collections, your collection’s extension must end in .html in order for redirect_to to properly process.

Chapter 1.4 - Gist

Liquid tag for displaying GitHub Gists in Jekyll sites: {% gist %}.


Add this line to your application’s Gemfile:

gem 'jekyll-gist'

And then execute:

$ bundle

Or install it yourself as:

$ gem install jekyll-gist

Finally, add the following to your site’s _config.yml:

  - jekyll-gist


Use the tag as follows in your Jekyll pages, posts and collections:

{% gist parkr/c08ee0f2726fd0e3909d %}

This will create the associated script tag:

<script src="https://gist.github.com/parkr/c08ee0f2726fd0e3909d.js"> </script>

You may optionally specify a filename after the gist_id:

{% gist parkr/c08ee0f2726fd0e3909d test.md %}

This will produce the correct URL to show just the specified file in your post rather than the entire Gist.

Pro-tip: If you provide a personal access token with Gist scope, as the environmental variable JEKYLL_GITHUB_TOKEN, Jekyll Gist will use the Gist API to speed up site generation.

Disabling noscript support

By default, Jekyll Gist will make an HTTP call per Gist to retrieve the raw content of the Gist. This information is used to propagate noscript tags for search engines and browsers without Javascript support. If you’d like to disable this feature, for example, to speed up builds locally, simply add the following to your site’s _config.yml:

  noscript: false

Chapter 1.5 - Emoji

GitHub-flavored Emoji plugin for Jekyll


Add the following to your site’s Gemfile

gem 'jemoji'

And add the following to your site’s _config.yml

  - jemoji

In any page or post, use emoji as you would normally, e.g.

I give this plugin two :+1:!


If you’d like to serve emoji images locally, or use a custom emoji source, you can specify so in your _config.yml file:

  src: "/assets/images/emoji"

See the Gemoji documentation for generating image files.

Chapter 1.6 - Mentions

@mentionable support for your Jekyll site


Add the following to your site’s Gemfile

gem 'jekyll-mentions'

And add the following to your site’s _config.yml

  - jekyll-mentions

In any page or post, use @mentions as you would normally, e.g.

Hey @benbalter, what do you think of this?

Note: Jekyll Mentions simply turns the @mentions into links, it does not notify the mentioned user.


Have your own social network? No problem. We allow you to configure the base URL of all the mentions.

To change it, add the following to your Jekyll configuration:

  base_url: https://twitter.com

If you’re lazy like me, you can use this shorthand:

jekyll-mentions: https://twitter.com

An example of Twitter mentions using jekyll-mentions:

  - jekyll-mentions

  base_url: https://twitter.com

Et voilà! Your mentions will now use that base URL instead of the default of https://github.com.

Chapter 1.7 - SEO Tag

A Jekyll plugin to add metadata tags for search engines and social networks to better index and display your site’s content.

What it does

Jekyll SEO Tag adds the following meta tags to your site:

While you could theoretically add the necessary metadata tags yourself, Jekyll SEO Tag provides a battle-tested template of crowdsourced best-practices.

What it doesn’t do

Jekyll SEO tag is designed to output machine-readable metadata for search engines and social networks to index and display. If you’re looking for something to analyze your Jekyll site’s structure and content (e.g., more traditional SEO optimization), take a look at The Jekyll SEO Gem.

Jekyll SEO tag isn’t designed to accommodate every possible use case. It should work for most site out of the box and without a laundry list of configuration options that serve only to confuse most users.


  1. Add the following to your site’s Gemfile:

ruby gem 'jekyll-seo-tag'

  1. Add the following to your site’s _config.yml:

yml gems: - jekyll-seo-tag

  1. Add the following right before </head> in your site’s template(s):

{% seo %}


The SEO tag will respect any of the following if included in your site’s _config.yml (and simply not include them if they’re not defined):

The SEO tag will respect the following YAML front matter if included in a post, page, or document:

Chapter 1.8 - GitHub Metadata

Access site.github metadata anywhere (…you have an internet connection).

First, a very special thanks to GitHub (especially Ben Balter and their legal team) for allowing me to open-source this code. :heart:


Usage of this gem is pretty straight-forward. Add it to your bundle like this:

gem 'jekyll-github-metadata'

Then go ahead and run bundle install. Once you’ve done that, add your repo & the gem to your _config.yml:

# or use PAGES_REPO_NWO in the env
repository: me/super-cool-project
gems: ['jekyll-github-metadata']

Then run jekyll like you normally would and your site.github.* fields should fill in like normal.


For some fields, like cname, you need to authenticate yourself. Luckily it’s pretty easy. You have 2 options:


These tokens are easy to use and delete so if you move around from machine-to-machine, we’d recommend this route. Set JEKYLL_GITHUB_TOKEN to your access token (with public_repo scope) when you run jekyll, like this:

$ JEKYLL_GITHUB_TOKEN=123abc [bundle exec] jekyll serve

2. ~/.netrc

If you prefer to use the good ol’ ~/.netrc file, just make sure the netrc gem is bundled and run jekyll like normal. So if I were to add it, I’d add gem 'netrc' to my Gemfile, run bundle install, then run bundle exec jekyll build. The machine directive should be api.github.com.

3. Octokit

We use Octokit to make the appropriate API responses to fetch the metadata. You may set OCTOKIT_ACCESS_TOKEN and it will be used to access GitHub’s API.

$ OCTOKIT_ACCESS_TOKEN=123abc [bundle exec] jekyll serve


Some site.github values can be overridden by environment variables.


Working with jekyll-github-metadata and GitHub Enterprise? No sweat. You can configure which API endpoints this plugin will hit to fetch data.

Part 2 - Tags

Chapter 2.1 - Avatar

A Jekyll plugin for rendering GitHub avatars

Jekyll Avatar makes it easy to add GitHub avatars to your Jekyll site by specifying a username. If performance is a concern, Jekyll Avatar is deeply integrated with the GitHub avatar API, ensuring avatars are cached and load in parallel.


Add the following to your site’s Gemfile:

gem 'jekyll-avatar'

And add the following to your site’s _config.yml file:

  - jekyll-avatar


Simply add the following, anywhere you’d like a user’s avatar to appear:

{% avatar [USERNAME] %}

With [USERNAME] being the user’s GitHub username:

{% avatar hubot %}

That will output:

<img class="avatar avatar-small" src="https://avatars3.githubusercontent.com/hubot?v=3&amp;s=40" alt="hubot" width="40" height="40" />


You can customize the size of the resulting avatar by passing the size argument:

{% avatar hubot size=50 %}

That will output:

<img class="avatar" src="https://avatars3.githubusercontent.com/hubot?v=3&amp;s=50" alt="hubot" width="50" height="50" />

Passing the username as variable

You can also pass the username as a variable, like this:

{% assign username="hubot" %}
{% avatar {{ username }} %}

Or, if the variables is in the page’s front matter:

{% avatar {{ page.username }} %}

Part 3 - Asset Pipeline

Chapter 3.1 - Assets

Jekyll 3 assets is an asset pipeline using Sprockets 3 to build especially for Jekyll 3. It utilizes new features of both Sprockets and Jekyll to achieve a clean and extensible assets platform for Jekyll.

Using Jekyll Assets with Jekyll

Add gem "jekyll-assets" to your Gemfile and add jekyll-assets to your _config.yml like the following:

- jekyll-assets


A lot of our configuration transforms based on the JEKYLL_ENV variable set in your environment. Such as digesting and whether or not to enable the CDN. Some of them can be explicitly overridden but a few cannot right now. You should set your JEKYLL_ENV=development on your development machine and JEKYLL_ENV=production when building to push.

    css: false | true | default - development: false, production: true
    js: false | true | default - development: false, production: true
  cache: false | directory | default: .asset-cache
  cdn: https://cdn.example.com
  skip_baseurl_with_cdn: false
  skip_prefix_with_cdn: false
  prefix: "/assets"
    - "*.png"
    - "bundle.css"
  digest: true
    - _assets/css
    - _assets/images
    - _assets/javascripts
    - _assets/stylesheets
    - _assets/fonts
    - _assets/img
    - _assets/js
    liquid: true | false | default: false
    automatic_img_size: true | false | default: true
    automatic_img_alt : true | false | default: true

Liquid Processing with your Jekyll context.

By default (whether features.liquid is true or false) we will process all files with the extension “.liquid”, so if you give us “.scss.liquid” we will parse the liquid and then we will parse the SCSS and finally output your “.css” file.

When features.liquid is set to true, we will process ALL files through Liquid, regardless of whether they have the “.liquid” extension. Use this at your own risk.

Cache Folder

If you plan to change the cache folder, please make sure to add that folder to your exclude list in Jekyll or you will generate over and over and over again, . folders are not ignored by default.


The listed resources in the example are all defaults. It should be noted that we append your sources instead of replace our resources with yours. So if you add “_assets/folder” then we will append that to our sources and both will work.

NOTE: if you use our _assets base folder container as a base folder for your sprockets, we will not append our sources, we will only use that folder as the sole source (base folder.)


You can force digesting with digest: true in your _config.yml


Bower Components

Modify your .bowerrc file and add:

  "directory": "_assets/bower"

And then add _assets/bower to your sources list and Sprockets will do the the rest for you… you can even //= require bower_asset.js. We will even compress them for you per normal if Sprockets supports it and allows us to.

You do not need to modify your .bowerrc file, you can optionally just add it to your sources list and it will work that way too! As long as it’s in your Jekyll folder.


Tag Example:

{% img src magick:2x alt:'This is my alt' %}
{% img src magick:2x alt:'This is my alt' sprockets:accept:image/gif %}

What do the colons mean? Proxies/Tags

Lets say we have sprockets proxies and sprockets allows you to proxy accept, if you send {% img src sprockets:accept:image/gif } then Sprockets find_asset will get { :accept => "image/gif" } but if you try to proxy “unknown” on sprockets we will raise a Proxy error. For more information then look at parser_spec.rb in the spec folder because it literally lays out the ground rules for our tags as a specification.

Current Proxies:

Liquid Variables

We support liquid arguments for tag values (but not tag keys), and we also support Liquid pre-processing (with your Jekyll context) sass/less/css files you need do nothing special for the preprocessing an entire file, it’s always done.

An example of using Liquid in your tags:

{% img '{{ image_path }}' %}
{% img '{{ image_path }}' proxy:key:'{{ value }}' %}
{% img {{\ image_path\ }} %}

An example of using Liquid in your SCSS:

.bg {
  background: url(asset_path(""));

You have full access to your entire Jekyll context from any liquid processing we do, so you can do whatever you like and be as dynamic as you like, including full loops and conditional Liquid based CSS since we pre-process your text files.

Getting a list of your assets and basic info from Liquid

We provide all your assets as a hash of Liquid Drops so you can get basic info that we wish you to have access to without having to prepare the class.

{{ assets["bundle.css"].content_type }} => "text/css"
{{ assets["images.jpg"].width  }} => 62
{{ assets["images.jpg"].height }} => 62

The current list of available accessors:

If you would like more, please feel free to add a pull request, at this time we will reject all pull requests that wish to add any digested paths as those are dynamically created when a proxy is ran so we can never predict it reliably unless we proxy and that would be a performance problem.

ERB Support

ERB Support is removed in favor of trying to get this included on Github Pages eventually (if I can.) Having ERB presents a security risk to Github because it would allow you to use Ruby in ways they don’t want you to.


There is a full suite of filters, actually, any tag and any proxy can be a filter by way of filter arguments, take the following example:

{{ src | img : "magick:2x magick:quality:92" }}


You can register and trigger hooks like so:

Jekyll::Assets::Hook.register :env, :init do
  # Your Work

Sass Helpers

Our currently supported helpers are:


Please note that some of these (if not all) have trouble with Rhino – therubyrhino so you would probably be best to just use Node.js or io.js at that point rather than trying to fight it.

Image Magick Proxy arguments:

Chapter 3.2 - Bootstrap Sass

A plugin to add the Twitter Bootstrap framework to your Jekyll site.


Add the following to your site’s Gemfile:

gem 'jekyll-bootstrap-sass'

And add the following to your site’s _config.yml file:

  - jekyll-bootstrap-sass


Create a .scss file (e.g., assets/style.scss), with the following:


@import 'bootstrap';

// (Your custom CSS Here)

When your site is built, Jekyll will automatically add the Bootstrap framework before it renders your site’s css. In the above example, the resulting file would be assets/style.css with Bootstrap’s CSS followed by your own.


By default, Jekyll Bootstrap SaSS will simply make the @import 'bootstrap'; directive available to your custom stylesheets so that you can more easily include Bootstrap’s CSS.

If you would like to use Bootstrap’s static assets (e.g., fonts, javascripts), you’ll need to add the following to your site’s _config.yml:

  assets: true

This will create /assets/fonts/bootstrap and assets/javascripts/bootstrap folders in the generated site, which you can include in your site’s header as you would any other javascript file or font.

If font’s aren’t loading properly, you may need to add the following before the import directive:

$icon-font-path: "http://hydepress.github.io/assets/fonts/bootstrap";

Specifying the Bootstrap version

Jekyll-bootstrap-sass relies on official bootstrap-sass Ruby gem. To specify the version of Bootstrap used, simply specify the bootstrap-sass gem version in your Gemfile.

Part 4 - Miscellaneous

Chapter 4.1 - Auth

A simple way to use GitHub OAuth to serve a protected Jekyll site to your GitHub organization

The problem

Jekyll and GitHub Pages are awesome, right? Static site, lightning fast, everything versioned in Git. What else could you ask for?

But what if you only want to share that site with a select number of people? Before, you were SOL. Now, simply host the site on a free, Heroku Dyno, and whenever someone tries to access it, it will Oauth them against GitHub, and make sure they’re a member of your Organization. Pretty cool, huh?


  1. A GitHub account (one per user)
  2. A GitHub Organization (of which members will have access to the Jekyll site)
  3. A GitHub Application (you can register one for free)
  4. A Heroku account (you can technically use this elsewhere, but the instructions are for Heroku)

Getting Started

Create a GitHub Application

  1. Navigate to the GitHub app registration page
  2. Give your app a name
  3. Tell GitHub the URL you want the app to eventually live at. If using a free Heroku account, this will be something like http://my-site.herokuapp.com
  4. Specify the callback URL; should be like this: https://my-site.herokuapp.com/auth/github/callback; note that this is https, not http.
  5. Hit Save, but leave the page open, you’ll need some of the information in a moment

Remember the ‘my-site’ part for later on when using heroku create. Also, my-site is often called ‘app-name’ in Heroku documentation.

Add Jekyll Auth to your site

  1. Within your new site repository or orphaned github branch (the branch could be named anything except ‘gh-pages’ since this would then be public on Github!), add gem 'jekyll-auth' to your Gemfile or if you don’t already have a Gemfile, create a file called Gemfile in the root of your site’s repository with the following content:

```ruby source “https://rubygems.org”

gem ‘jekyll-auth’ ```

  1. cd into your project’s directory and run bundle install. If you get an error using bundle install, see Troubleshooting below.

  2. Run bundle exec jekyll-auth new which will copy the necessary files to set up the server

Setting up hosting with Heroku


Run bundle exec jekyll-auth setup --client_id XXX --client_secret XXX --org_name XXX

(or --team_id XXX)


  1. You may need to add and commit the files generated by jekyll-auth new to Git before continuing
  2. Make sure you have the Heroku toolbelt installed
  3. Run heroku create my-site from your site’s directory; make sure my-site matches what you specified in the Github application registration above.
  5. git push heroku, or if you are maintaining the site in an orphaned branch of your Github repo (say ‘heroku-pages’), do git push heroku heroku-pages:master
  6. heroku open to open the site in your browser

Find the Organization ID (needed to find Team ID)

If you need to find an organization’s ID, you can use the following cURL command:

curl https://api.github.com/orgs/{org_name}

Finding the Team ID

If you need help finding a team’s numeric ID, you can use the jekyll-auth team_id command.

For example, to find the team ID for @jekyll/maintainers you’d run the command:

jekyll-auth team_id --org jekyll --team maintainers

You’ll want to add a personal access token to your .env file so that Jekyll-Auth can make the necessary API request, but the command will run you through the process if you do not provide this.



Don’t want to require authentication for every part of your site? Fine! Add a whitelist to your Jekyll’s _config.yml_ file:

    - drafts?

jekyll_auth.whitelist takes an array of regular expressions as strings. The default auth behavior checks (and blocks) against root (/). Any path defined in the whitelist won’t require authentication on your site.

What if you want to go the other way, and unauthenticate the entire site except for certain portions? You can define some regex magic for that:

    - "^((?!draft).)*$"

There is also a more extensive article containing installation instructions for Jekyll-Auth and a second one on how to find your GitHub team ID.

Requiring SSL

If you’ve got SSL set up, simply add the following your your _config.yml file to ensure SSL is enforced.

  ssl: true

Using a custom 404

Just like GitHub Pages, Jekyll Auth will honor a custom 404 page, if it’s generated as /404.html in the built site.

Running locally

Want to run it locally?

Without authentication

Just run jekyll serve as you would normally.

With authentication

  1. export GITHUB_CLIENT_ID=[your github app client id]
  2. export GITHUB_CLIENT_SECRET=[your github app client secret]
  3. export GITHUB_ORG_NAME=[org name] or export GITHUB_TEAM_ID=[team id] or export GITHUB_TEAM_IDS=1234,5678
  4. jekyll-auth serve

Pro-tip #1: For sanity’s sake, and to avoid problems with your callback URL, you may want to have two apps, one with a local Oauth callback, and one for production if you’re going to be testing auth locally.

Pro-tip #2: Jekyll Auth supports dotenv out of the box. You can create a .env file in the root of site and add your configuration variables there. It’s ignored by .gitignore if you use jekyll-auth new, but be sure not to accidentally commit your .env file. Here’s what your .env file might look like:


Under the hood

Every time you push to Heroku, we take advantage of the fact that Heroku automatically runs the rake assets:precompile command (normally used for Rails sites) to build our Jekyll site and store it statically, just like GitHub pages would.

Anytime a request comes in for a page, we run it through Sinatra (using the _site folder as the static file folder, just as public would be normally), and authenticate it using sinatra_auth_github.

If they’re in the org, they get the page. Otherwise, all they ever get is the bouncer.

Upgrading from Jekyll Auth < 0.1.0

  1. cd to your project directory
  2. rm config.ru
  3. rm Procfile
  4. Remove any Jekyll Auth specific requirements from your Gemfile
  5. Follow the instructions above to get started
  6. When prompted, select “n” if Heroku is already set up


remote:        Configuration file: none
remote:                     ERROR: YOUR SITE COULD NOT BE BUILT:
remote:                            ------------------------------------
remote:                            Invalid date '0000-00-00': Post '/vendor/bundle/ruby/2.0.0/gems/jekyll-2.5.3/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb' does not have a valid date in the filename.
heroku git:remote -a my-site 

Chapter 4.2 - Scholar

Jekyll-Scholar is for all the academic bloggers out there. It is a set of extensions to Jekyll, the awesome, blog aware, static site generator; it formats your bibliographies and reading lists for the web and gives your blog posts citation super-powers.

For additional features you may also want to take a look at jekyll-scholar-extras.

Already using Jekyll-Scholar and interested to help out? Please get in touch with us if you would like to become a maintainer!


$ [sudo] gem install jekyll-scholar

Or add it to your Gemfile:

gem 'jekyll-scholar'

Github Pages

Note that it is not possible to use this plugin with the default Github pages workflow. Github does not allow any but a few select plugins to run for security reasons, and Jekyll-Scholar is not among them. You will have to generate your site locally and push the results to the master resp. gh-pages branch of your site repository. You can keep sources, configuration and plugins in a separate branch; see e.g. here for details.


Install and setup a new Jekyll directory (see the Jekyll-Wiki for detailed instructions). To enable the Jekyll-Scholar add the following statement to a file in your plugin directory (e.g., to _plugins/ext.rb):

require 'jekyll/scholar'

Alternatively, add jekyll-scholar to your gem list in your Jekyll configuration:

gems: ['jekyll/scholar']

In your configuration you can now adjust the Jekyll-Scholar settings. The default configuration is as follows:

  style: apa
  locale: en
  sort_by: none
  order: ascending
  group_by: none
  group_order: ascending
  source: ./_bibliography
  bibliography: references.bib
  bibliography_template: ""
  replace_strings: true
  join_strings:    true
  use_raw_bibtex_entry: false
  - superscript
  - latex
  details_dir:    bibliography
  details_layout: bibtex.html
  details_link:   Details
  query: "@*"

You can use any style that ships with CiteProc-Ruby by name (e.g., apa, mla, chicago-fullnote-bibliography) which is usually the filename as seen here sans the .csl ending; note that you have to use dependent/style if you want to use one from that directory. Alternatively you can add a link to any CSL style (e.g., you could link to any of the styles available at the official CSL style repository).

The locale settings defines what language to use when formatting your references (this typically applies to localized terms, e.g., ‘Eds.’ for editors in English).

The source option indicates where your bibliographies are stored; bibliography is the name of your default bibliography. For best results, please ensure that your Bibliography is encoded as ASCII or UTF-8.

The use_raw_bibtex_entry option will disable parsing of Liquid tags that are embedded in the Bibtex fields. This option provides a way to circumvent the problem that the double braces functionality of BibTex is accidentally parsed by Liquid, while it was intended to keep the exact capitalization style.

The sort_by and order options specify if and how bibliography entries are sorted. Entries can be sorted on multiple fields, by using a list of keys, e.g. sort_by: year,month. Ordering can be specified per sort level, e.g. order: descending,ascending will sort the years descending, but per year the months are ascending. If there are more sort keys than order directives, the last order entry is used for the remaining keys.

The group_by and group_order options specify how bibliography items are grouped. Grouping can be multi-level as well, e.g. group_by: type, year groups entries per publication type, and within those groups per year. Ordering for groups is specified in the same way as the sort order. Publication types – specified with group key type, can be ordered by adding type_order to the configuration. For example, type_order: article,techreport lists journal articles before technical reports. Types not mentioned in type_order are considered smaller than types that are mentioned. Types can be merge in one group using the type_aliases setting. By default phdthesis and mastersthesis are grouped as thesis. By using, for example, type_aliases: { inproceeding => article}, journal and conference articles appear in a single group. The display names for entry types are specified with type_names. Names for common types are provided, but they can be extended or overridden. For example, the default name for article is Journal Articles, but it can be changed to Papers using type_name: { article => 'Papers' }.

The bibtex_filters option configures which BibTeX-Ruby formatting filters values of entries should be passed through. This defaults to the latex filter which converts LaTeX character escapes into unicode, and superscript which converts the \textsuperscript command into a HTML <sup> tag.


Once you have loaded Jekyll-Scholar, all files with the extension .bib or .bibtex will be converted when you run Jekyll (don’t forget to add a YAML header to the files); the file can contain regular HTML or Markdown and BibTeX entries; the latter will be formatted by Jekyll-Scholar according to the citation style and language defined in your configuration file.

For example, if you had a file bibliography.bib in your root directory:


  title     = {The Ruby Programming Language},
  author    = {Flanagan, David and Matsumoto, Yukihiro},
  year      = {2008},
  publisher = {O'Reilly Media}

It would be converted to bibliography.html with the following content:

<h1 id='references'>References</h1>

<p>Flanagan, D., &#38; Matsumoto, Y. (2008). <i>The Ruby Programming Language</i>. O&#8217;Reilly Media.</p>

This makes it very easy for you to add your bibliography to your Jekyll-powered blog or website.

If you are using other converters to generate your site, don’t worry, you can still generate bibliographies using the bibliography tag. In your site or blog post, simply call:

{% bibliography %}

This will generate your default bibliography; if you use multiple, you can also pass in a name to tell Jekyll-Scholar which bibliography it should render.

Let’s say you have two bibliographies stored in _bibliography/books.bib and _bibliography/papers.bib; you can include the bibliographies on your site by respectively calling {% bibliography --file books %} and {% bibliography --file papers %}. For example, you could have a file references.md with several reference lists:

title: My References

{{ page.title }}

The default Bibliography

{% bibliography %}

Secondary References

{% bibliography --file secondary %}

Finally, the bibliography tag supports an optional filter parameter. This filter takes precedence over the global filter defined in your configuration.

{% bibliography --query @*[year=2013] %}

The example above would print a bibliography of all entires published in the year 2013. Of course you can also combine the file and filter parameters like this:

{% bibliography -f secondary -q @*[year=2013] %}

This would print the publications from 2013 of the bibliography at _bibliography/secondary.bib.

For more details about filters, see the corresponding section below or consult the BibTeX-Ruby documentation.

If you need to limit the number of entries in your bibliography, you can use the --max option:

{% bibliography --max 5 %}

This would generate a bibliography containing only the first 5 entries of your bibliography (after query filters and sort options have been applied). Limiting entries is disabled if grouping is active.

Bibliography Template

Your bibliography is always rendered as an ordered list. Additionally, each reference is wrapped in an HTML tag (span by default but you can change this using the reference_tagname setting) with the cite key as id. The reference string itself is governed by the rules in your CSL style but you can also customize the main template a little bit. By default, the template is {{reference}} – this renders only the reference tag. The template uses Liquid to render and, in addition to the reference, exposes the cite-key (as key), the entry’s type, the index in the bibliography, and the link to file repository as link. Thus, you could customize the template in your configuration as follows:

  bibliography_template: <abbr>[{{key}}]</abbr>{{reference}}

This would be processed into something like:

<li><abbr>[ruby]</abbr><span id="ruby">Matsumoto, Y. (2008). <i>The Ruby Programming Language</i>. O&#8217;Reilly Media.</span></li>

If you have more complex requirements, it quickly becomes tedious to have the template inside the configuration; for this reason, you can also put the bibliography template into your layouts directory. Jekyll-Scholar will load this template if the option set in your configuration matches an existing layout (without the file extension). That is to say, if you set:

  bibliography_template: bib

And there is a file _layouts/bib.html (or with another extension) the contents of this file will be used as the template. Please note that it is important for this file to contain the YAML front matter! For example, this would be a more complex template file:

{{ reference }}

{% if entry.abstract %}
<p>{{ entry.abstract }}</p>
{% endif %}

<pre>{{ entry.bibtex }}</pre>

You can also override the default bibliography template, by passing the --template or -T option parameter to the bibliography tag.


If you want to reference books or papers from your bibliography in your blog posts, Jekyll-Scholar can help you, too. Simply use the cite tag with the appropriate key of the item you want to cite and Jekyll-Scholar will create a formatted citation reference for you. For a quick example, take following blog post:

layout: default
title: A Blogging Scholar

{{ page.title }}

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis 'aute irure dolor in reprehenderit in voluptate' {% cite derrida:purveyor %}
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, 'sunt in culpa qui officia deserunt mollit anim id est
laborum' {% cite rabinowitz %}.

Duis 'aute irure dolor in reprehenderit in voluptate' {% cite breton:surrealism %}
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, 'sunt in culpa qui officia deserunt mollit anim id est
laborum' {% cite rainey %}.


{% bibliography %}

Note that this will print your entire bibliography in the Reference section. If you would like to include only those entries you cited on the page, pass the cited option to the bibliography tag:

{% bibliography --cited %}

By default, the --cited option will still sort your bibliography if you set the sort option. Especially for styles using citation numbers, this is usually not the desired behaviour. In such cases you can use --cited_in_order instead of --cited and your bibliography will contain all cited items in the order they were cited on the page.

For longer quotes, Jekyll-Scholar provides a quote tag:

{% quote derrida:purveyor %}
Lorem ipsum dolor sit amet, consectetur adipisicing elit,
sed do eiusmod tempor.

Lorem ipsum dolor sit amet, consectetur adipisicing.
{% endquote %}

For example, this could be rendered as:

  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit,<br/>
  sed do eiusmod tempor.</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing.</p>
    <a href="#derrida:purveyor">(Derrida, 1975)</a>

Multiple citation

You can cite multiple items in a single citation by referencing all ids of the items you wish to quote separated by spaces. For example, {% cite ruby microscope %} would produce a cite tag like:

<a href="#ruby">(Flanagan &amp; Matsumoto 2008; Shaughnessy 2013)</a>

Suppressing author names

Sometimes you want to suppress author names in a citation, because the name has already been mentioned in your text; for such cases Jekyll-Scholar provides the --suppress_author option (short form: -A): ...as Matz explains {% cite ruby -A -l 42 %} would produce something like: ...as Matz explains (2008, p. 42).

Page numbers and locators

If you would like to add page numbers to your citation, you can use the -l or --locator option. For example, {% cite ruby -l 23-5 %} would produce a citation like (Matsumoto, 2008, pp. 23-5).

When quoting multiple items (see above) you can add multiple locators after the list of ids. For example, {% cite ruby microscope -l 2 -l 24 & 32 %}.

Displaying formatted references

If you want to display the full formatted reference entry, you can use the reference tag. For example, given the following Bibtex entry,

  title     = {The Ruby Programming Language},
  author    = {Flanagan, David and Matsumoto, Yukihiro},
  year      = {2008},
  publisher = {O'Reilly Media}

using {% reference ruby %} anywhere in your page, it will print “Flanagan, D., & Matsumoto, Y. (2008). The Ruby Programming Language.. O’Reilly Media” (the exact result depends on your formatting style).

The reference tag accepts the same –file/-f parameter as the bibliography tag. This can be handy if you want to use a special BibTeX file as input for a specific page. As an example, the tag

{% reference ruby --file /home/foo/bar.bib %}

will attempt to read the key ruby from file /home/foo/bar.bib. It will not fallback to the default BibTeX file.

Citation pointing to another page in your site

In some cases, you might want your citation to link to another page on your cite (ex. a separate works cited page). As a solution, Jekyll-Scholar provides the --relative tag. For example, if you wanted the link to point to an ID in a bibliography.html page, you would use:

{% cite ruby --relative bibliography.html %}

Multiple bibliographies within one document (like multibib.sty)

When you have multiple {% bibliography %} sections in one file, Jekyll-Scholar will generate several lists containing the same publications that have the same id attributes. As a result, when you cite a reference the link to an id attribute cannot be resolved uniquely. Your browser will always take you take you to the first occurrence of the id. Moreover, valid HTML requires unique id attributes. This scenario may happen, for example, if you cite the same reference in different blog posts, and all of these posts are shown in one html document.

As a solution, Jekyll-Scholar provides the --prefix tag. In your first post you might cite as

title: Post 1
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis 'aute irure dolor in reprehenderit in voluptate'
{% cite derrida:purveyor --prefix post1 %} velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, 'sunt in culpa qui officia deserunt mollit anim id
est laborum' {% cite rabinowitz --prefix post1 %}.


{% bibliography --cited --prefix post1 %}

For the second blog post you would cite as follows:

title: Post 2
Duis 'aute irure dolor in reprehenderit in voluptate'
{% cite rabinowitz --prefix post2 %} velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, 'sunt in culpa qui officia deserunt mollit anim id
est laborum' {% cite rainey --prefix post2  %}.


{% bibliography --cited --prefix post2 %}

Even though both posts cite ‘rabinowitz’, both citations will be assigned unique identifiers linking to the respective references section, although both posts will be rendered into a single HTML document.

File Repositories

File repository support was added to Jekyll-Scholar starting at version 2.0. Currently, if you have a folder in your site that contains PDF or Postscript files of your papers, you can use the configuration option repository to indicate this directory. When generating bibliographies, Jekyll-Scholar will look in that folder to see if it contains a filename matching each entry’s BibTeX key: if it does, the path to that file will be exposed to the bibliography template as the link property.

Since version 4.1.0 repositories are not limited to PDF and PS files. These files are mapped to the links property in your bibliography template. Here is an example of template that utilizes this feature to link to supporting material in a ZIP archive:

{{ reference }} [<a href="{{links.zip}}">Supporting Materials</a>]

Detail Pages

If your layouts directory contains a layout file for bibliography details (the details_layout configuration options), Jekyll-Scholar will generate a details page for each entry in you main bibliography. That is to say, if your bibliography contains the following entry:

  title     = {The Ruby Programming Language},
  author    = {Flanagan, David and Matsumoto, Yukihiro},
  year      = {2008},
  publisher = {O'Reilly Media}

Then a page ‘bibliography/ruby.html’ will be generated according to your details page layout. In the layout file, you have access to all fields of your BibTeX entry. Here is an example of a details page layout:

  <h1>{{ page.entry.title }}</h1>
  <h2>{{ page.entry.author }}</h2>
  <p>{{ page.entry.abstract }}</p>

When Jekyll-Scholar generates detail pages, it also adds links to each entry’s detail page to the generated bibliography. You can alter the name of the link via the ‘details_link’ configuration option.

Jekyll-Scholar also provides a Liquid tag for conveniently adding links to individual detail pages. For example, if you would like to add a simple link to one of the items in your bibliography on a page or in a blog post you can use the cite_details tag to generate the link. For this to work, you need to pass the BibTeX key of the element you want to reference to the tag and, optionally, provide a text for the link (the default text can be set via the ‘details_link’ configuration option).

Duis 'aute irure dolor in reprehenderit in voluptate' velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident {% cite_details key --text Click Here For More Details %}.

Bibliography Filters

By default, Jekyll-Scholar includes all entries in you main BibTeX file when generating bibliographies. If you want to include only those entries matching certain criteria, you can do so by adjusting the ‘query’ configuration option. For example:

query: "@book" #=> includes only books
query: "@article[year>=2003]" #=> includes only articles published 2003 or later
query: "@*[url]" #=> includes all entries with a url field
query: "@*[status!=review]" #=> includes all entries whose status field is not set to 'review'
query: "@book[year <= 1900 && author ^= Poe]" #=> Books published before 1900 where the author matches /Poe/
query: "!@book" #=> includes all entries with a type other than book

Please note that some of these queries require BibTeX-Ruby 2.3.0 or later versions. You can also overwrite the configuration’s query parameter in each bibliography tag individually as described above.

Part 5 - Command Line Tools

Chapter 5.1 - drjekyll - the missing static site theme package manager

jekyll command line tool


The drjekyll gem includes a command line tool that lets you manage static site theme packages. Try:

$ drjekyll --help      # or
$ drj -h

Resulting in:

    drjekyll/drj - jekyll command line tool .:. the missing static site theme package manager

    drjekyll/drj [global options] command [command options] [arguments...]


    --help    - Show this message
    --verbose - (Debug) Show debug messages
    --version - Display the program version

    list, ls, l             - List themes
    new, n                  - Download 'n' setup (unzip/unpack) theme
    help                    - Shows a list of commands or help for one command

    download, dl, d, get, g - (Debug) Step 1: Download theme; .zip archive saved in working folder (./)
    unzip, setup, s         - (Debug) Step 2: Setup (unzip/unpack) theme; uses .zip archive in working folder (./)


List ThemesNew Theme

List Themes Command - list, ls, l


$ drjekyll list    # or
$ drjekyll ls      # or
$ drjekyll l       # or
$ drj l

Resulting in:

  1..Planet Jekyll's Starter (Minimal) (starter | planetjekyllsstarterminimal) by Gerald Bauer - #white 
  2..Dr Jekyll's Minimal (minimial | drjekyllsminimal) by Gerald Bauer - #white 
  3..Dr Jekyll's Bootstrap (bootstrap | drjekyllsbootstrap) by Gerald Bauer - #bootstrap #scss #white 
  4..Dr Jekyll's Classics Book (classics | drjekyllsclassicsbook) by Gerald Bauer - #books #white 
  5..Poole (poole) by Mark Otto - #poole 
  6..Poole's Hyde (pooleshyde) by Mark Otto - #poole 
  7..Poole's Lanyon (pooleslanyon) by Mark Otto - #poole 
  8..Beautiful Jekyll (beautifuljekyll) by Dean Attali

Note: You can filter by name or tags; just add the query e.g.:

$ drjekyll list resume    # or
$ drjkeyll ls resume      # or
$ drjkeyll l resume       # or
$ drj l resume

Resulting in:

 68..Resume Cards (resumecards) by Elle Kasai - #resume
104..iCard Resume (icardresume) by Dong Liang - #resume 
109..Resume (resume) by Joel Glovier - #resume 

New Theme Command - new, n

To download and install (unzip/unpack) a theme archive use:

$ drjekyll new starter    # or
$ drjekyll n starter      # or
$ drj n starter

This will download the starter.zip to your working folder and unzip the archive into the ./starter folder.

More Examples

To download and install (unzip/unpack):

  7..Poole's Lanyon (lanyon | pooleslanyon) by Mark Otto - #poole 


$ drjekyll new lanyon     # or
$ drjekyll n lanyon       # or
$ drj      n lanyon

To download and install (unzip/unpack):

  8..Beautiful Jekyll (beautifuljekyll) by Dean Attali


$ drjekyll new beautifuljekyll   # or
$ drjekyll n beautifuljekyll     # or
$ drj      n beautifuljekyll

And so on and so forth.

More Themes

See the Dr. Jekyll’s Themes directory.

More Quick Starter Wizard Scripts

See the Mr. Hyde’s Scripts library.


Just install the gem:

$ gem install drjekyll

Chapter 5.2 - mrhyde - static site quick starter script wizard

jekyll command line tool


The mrhyde-tools gem includes a command line tool that lets you run static site quick starter scripts. Try:

$ mrhyde --help      # or
$ mrh -h

Resulting in:

    mrh/mrhyde - jekyll command line tool .:. the static site quick starter script wizard

    mrhyde [global options] command [command options] [arguments...]


    --help            - Show this message
    --test, --dry_run - (Debug) Dry run; run script in simulation for testing
    --verbose         - (Debug) Show debug messages
    --version         - Display the program version

    new, n - Run static site quick starter script

    help   - Shows a list of commands or help for one command
    test   - (Debug) Test command suite


New Wizard

New Wizard Command - new, n

To run a static site quick starter wizard script to download and install (unzip/unpack) a theme archive and configure a static site ready-to-use. Try:

$ mrhyde new starter    # or
$ mrhyde n starter      # or
$ mrh n starter

This will download the starter.rb wizard script from the Mr. Hyde’s Scripts repo and run through all steps e.g.:

Welcome, before setting up your site Mr. Hyde will ask you some questions.

Q: What's your site's title? [Your Site Title]:  Another Beautiful Static Site
Q: What's your name? [Henry Jekyll]: Edward Hyde
Q: Select your theme:
     1 - Starter
     2 - Bootstrap
     3 - Minimal
   Your choice (1-3)? [1]: 2 

Thanks! Ready-to-go. Stand back.

  Downloading Dr. Jekyll's Bootstrap Theme...
  Setting up Dr. Jeykll's Bootstrap Theme..
  Updating settings in _config.yml...
    title: "Another Beautiful Static Site"
    author.name: "Edward Hyde"

That’s it. Now use:

$ cd starter
$ jekyll serve

And open up your new static site in your browser.

More Quick Starter Wizard Scripts

See the Mr. Hyde’s Scripts library.

More Themes

See the Dr. Jekyll’s Themes directory.


Just install the gem:

$ gem install mrhyde-tools

Part 6 - WordPress

Chapter 6.1 - WordPress to Jekyll Exporter

One-click WordPress plugin that converts all posts, pages, taxonomies, metadata, and settings to Markdown and YAML which can be dropped into Jekyll.

A Note

Many shared hosts may use PHP 5.2 by default. WordPress to Jekyll Export requires PHP 5.3 or greater.

If you get an error message that looks like unexpected T_STRING or expecting T_CONSTANT_ENCAPSED_STRING, you need to update your PHP version. In a shared hosting environment, you should be able to change the version of PHP used by simply toggling the setting in the host’s control panel.

PHP 5.2 lost support from the PHP project itself more than five years ago. You’ll need to be running at least PHP 5.3 which adds namespace support (the reason it’s breaking), but I’d recommend at least 5.5 (or the latest your host supports) as it’s the oldest supported version: https://en.wikipedia.org/wiki/PHP#Release_history



  1. Place plugin in /wp-content/plugins/ folder
  2. Activate plugin in WordPress dashboard
  3. Select Export to Jekyll from the Tools menu

Command-line Usage

If you’re having trouble with your web server timing out before the export is complete, or if you just like terminal better, you may enjoy the command-line tool.

It works just like the plugin, but produces the zipfile on STDOUT:

php jekyll-export-cli.php > jekyll-export.zip

If using this method, you must run first cd into the wordpress-to-jekyll-exporter directory.

Alternatively, if you have WP-CLI installed, you can run:

wp jekyll-export > export.zip

The WP-CLI version will provide greater compatibility for alternate WordPress environments, such as when wp-content isn’t in the usual location.

Custom post types

To export custom post types, you’ll need to add a filter to do the following:

add_filter( 'jekyll_export_post_types', array('posts', 'pages', 'you-custom-post-type') );

The custom post type will be exported as a Jekyll collection. You’ll need to initialize it in the resulting Jekyll site’s _config.yml.

Chapter 6.2 - WordPress <--> GitHub Sync


A WordPress plugin to sync content with a GitHub repository (or Jekyll site)

Ever wish you could collaboratively author content for your WordPress site (or expose change history publicly and accept pull requests from your readers)?

Looking to tinker with Jekyll, but wish you could use WordPress’s best-of-breed web editing interface instead of Atom? (gasp!)

Well, now you can! Introducing WordPress <–> GitHub Sync!

WordPress <–> GitHub Sync does three things:

  1. Allows content publishers to version their content in GitHub, exposing “who made what change when” to readers
  2. Allows readers to submit proposed improvements to WordPress-served content via GitHub’s Pull Request model
  3. Allows non-technical writers to draft and edit a Jekyll site in WordPress’s best-of-breed editing interface

WordPress <–> GitHub sync might be able to do some other cool things:

How it works

The sync action is based on two hooks:

  1. A per-post sync fired in response to WordPress’s save_post hook which pushes content to GitHub
  2. A sync of all changed files triggered by GitHub’s push webhook (outbound API call)


Using the WordPress Dashboard

  1. Navigate to the ‘Add New’ in the plugins dashboard
  2. Search for ‘WordPress GitHub Sync’
  3. Click ‘Install Now’
  4. Activate the plugin on the Plugin dashboard

Uploading in WordPress Dashboard

  1. Download wordpress-github-sync.zip from the WordPress plugins repository.
  2. Navigate to the ‘Add New’ in the plugins dashboard
  3. Navigate to the ‘Upload’ area
  4. Select wordpress-github-sync.zip from your computer
  5. Click ‘Install Now’
  6. Activate the plugin in the Plugin dashboard

Using FTP

  1. Download wordpress-github-sync.zip
  2. Extract the wordpress-github-sync directory to your computer
  3. Upload the wordpress-github-sync directory to the /wp-content/plugins/ directory
  4. Activate the plugin in the Plugin dashboard

Installing from Source

Install the plugin and activate it via WordPress’s plugin settings page.

  1. cd wp-content/plugins
  2. git clone https://github.com/benbalter/wordpress-github-sync.git
  3. cd wordpress-github-sync && composer install
  4. Activate the plugin in Wordpress’ Dashboard > Plugins > Installed Plugins

Configuring the plugin

  1. Create a personal oauth token with the public_repo scope. If you’d prefer not to use your account, you can create another GitHub account for this.
  2. Configure your GitHub host, repository, secret (defined in the next step), and OAuth Token on the WordPress <–> GitHub sync settings page within WordPress’s administrative interface. Make sure the repository has an initial commit or the export will fail.
  3. Create a WebHook within your repository with the provided callback URL and callback secret, using application/json as the content type. To set up a webhook on GitHub, head over to the Settings page of your repository, and click on Webhooks & services. After that, click on Add webhook.
  4. Click Export to GitHub or if you use WP-CLI, run wp wpghs export all # from the command line, where # = the user ID you’d like to commit as.

Frequently Asked Questions

Markdown Support

WordPress <–> GitHub Sync exports all posts as .md files for better display on GitHub, but all content is exported and imported as its original HTML. To enable writing, importing, and exporting in Markdown, please install and enable WP-Markdown, and WordPress <–> GitHub Sync will use it to convert your posts to and from Markdown.

You can also activate the Markdown module from Jetpack or the standalone JP Markdown to save in Markdown and export that version to GitHub.

Importing from GitHub

WordPress <–> GitHub Sync is also capable of importing posts directly from GitHub, without creating them in WordPress before hand. In order to have your post imported into GitHub, add this YAML Frontmatter to the top of your .md document:

post_title: 'Post Title'
layout: post_type_probably_post
published: true_or_false
Post goes here.

and fill it out with the data related to the post you’re writing. Save the post and commit it directly to the repository. After the post is added to WordPress, an additional commit will be added to the repository, updating the new post with the new information from the database.

Note that WordPrss<–>GitHub Sync will only import posts from the master branch. Changes on other branches will be ignored.

If WPGHS cannot find the author for a given import, it will fallback to the default user as set on the settings page. Make sure you set this user before you begin importing posts from GitHub. Without it set, WPGHS will default to no user being set for the author as well as unknown-author revisions.

Custom Post Type & Status Support

By default, WordPress <–> GitHub Sync only exports published posts and pages. However, it provides a number of hooks in order to customize its functionality. Check out the wiki for complete documentation for these actions and filters.

If you want to export additional post types or draft posts, you’ll have to hook into the filters wpghs_whitelisted_post_types or wpghs_whitelisted_post_statuses respectively.

In wp-content, create or open the mu-plugins folder and create a plugin file there called wpghs-custom-filters.php. In it, paste and modify the below code:

 * Plugin Name:  WordPress-GitHub Sync Custom Filters
 * Plugin URI:   https://github.com/benbalter/wordpress-github-sync
 * Description:  Adds support for custom post types and statuses
 * Version:      1.0.0
 * Author:       James DiGioia
 * Author URI:   https://jamesdigioia.com/
 * License:      GPL2

add_filter('wpghs_whitelisted_post_types', function ($supported_post_types) {
  return array_merge($supported_post_types, array(
    // add your custom post types here

add_filter('wpghs_whitelisted_post_statuses', function ($supported_post_statuses) {
  return array_merge($supported_post_statuses, array(
    // additional statuses available: https://codex.wordpress.org/Post_Status

If you want to add a link to your posts on GitHub, there are 4 functions WordPress<–>GitHub Sync makes available for you to use in your themes or as part of the_content filter:

All four of these functions must be used in the loop. If you’d like to retrieve these URLs outside of the loop, instantiate a new WordPress_GitHub_Sync_Post object and call github_edit_url or github_view_url respectively on it:

// $id can be retrieved from a query or elsewhere
$wpghs_post = new WordPress_GitHub_Sync_Post( $id );
$url = $wpghs_post->github_view_url();

If you’d like to include an edit link without modifying your theme directly, you can add one of these functions to the_content like so:

add_filter( 'the_content', function( $content ) {
  if( is_page() || is_single() ) {
    $content .= get_the_github_edit_link();
  return $content;
}, 1000 );

Additional Customizations

There are a number of other customizations available in WordPress <–> GitHub Sync, including the commit message and YAML front-matter. Want more detail? Check out the wiki.