This post is the part 1 of the tutorial collection on how to migrate from Wordpress to Jekyll.

Install Jekyll locally

See the Jekyll homepage

$ ruby -v && gem -v # just making sure we got ruby and gem installed
$ gem install bundler jekyll

Publish to

Github can be used to host Jekyll static websites, on

Just push to a Github repo on the master branch, and enable Pages on Gihtub in Settings > GitHub Pages

Create custom domain with https

2 steps:

  1. Activate it in the repo settings, it’s going to create a CNAME file with your custom domain:

  2. Then, in your hosting provider DNS settings (such as OVH), configure a CNAME DNS entry with your URL: todo

PS: For HTTPS it’s automatic since 2016, it might take up to a day to propagate. Be sure to enable this option in the repo settings.

Migrate posts content from Wordpress

I used

Edit Server config for redirects

Posts on old wordpress site were hosted on, but now they are hosted on

A quick Nginx rule did the trick, to ensure backward compatibility:

location ~ ^/2018 {
	rewrite ^$request_uri? permanent;

Migrate Wordpress default functionalities

Jekyll comes as a pretty bare and simple blogging plateform. You can create posts and categories, but there’s no SEO, no categories browsing or even comments. I had to dig a little deeper to find what I was looking for.

Add Jekyll SEO

This one is easy and automatic as it comes as a Jekyll plugin. Jekyll plugins are installed by adding an entry in _config.yml and Gemfile, then running bundle install. See Jekyll SEO install details.

Add categories

This one is a little bit more complicated. Categories in wordpress allow us to browse, search and display posts. This is not a native feature of Jekyll.

First we need a page with all categories. I reused this very good tutorial on Jekyll categories where the idea is to have a /categories.html with a Jekyll standard loop {% for category in page.categories %}.

I also added this bit at the top and the bottom of each post, in order to display the categories of a post: todo

{% for category in page.categories %}
  <a href="{{site.baseurl}}/categories?id={{category|slugize}}"
    class="badge badge-info">
    <i class="fas fa-tag"></i> {{category}}
  {% unless forloop.last %}&nbsp;{% endunless %}
{% endfor %}


Noticed the /categories?id= part? With a bit of javascript, we are able to display a specific category: todo

  var hash =[^&]*)/i)[1].replace(/%20/g, ' ');
  var categories = document.getElementsByClassName('category');
  for(var category of categories){
    if( != hash){
      category.className += ' d-none'; // d-none is the bootstrap 4 class to hide an element


Add Previous/Next


<!-- Previous post -->
{% if page.previous %}
    {% assign previous = page.previous %}
{% else %}
    {% assign previous = site.posts[0] %}
{% endif %}
<a href="{{site.baseurl}}{{previous.url}}">{{previous.title}}</a>

<!-- Next post -->
{% if %}
    {% assign next = %}
{% else %}
    {% assign last lastPostIndex = site.posts | size | minus: 1 %}
    {% assign next = site.posts[lastPostIndex] %}
{% endif %}
<a href="{{site.baseurl}}{{next.url}}">{{next.title}}</a>


Add comments


Add robots.txt


User-agent: *


<a href="" target="_blank">Improve this page</a>

Migrate HTML to Markdown


Find:     [ \t]*<h2>\s*([\w  \-]+)\s*</h2>
Replace:  ## $1
Find:     [ \t]*<h3>\s*([\w  \-]+)\s*</h3>
Replace:  ### $1

Links (URL regex from

Find:     <a .*href="([\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+?)".*>(.+?)</a>
Replace:  [$2]($1)

Migrate Crayon Code Highlighter

Regex for code blocks:

Find:    [ \t]*<pre class="lang:(\w+) decode:true ?">(.*)\n
Replace: ```$1\n$2

Find:    \n?</pre>
Replace: \n```

Find:    <span class="lang:\w+ decode:true crayon-inline">([/\w\.\-><$]+)</span>
Replace: `$1`

Find:    (&#8216;|&#8217;|&#8220;|&#8221;)
Replace: '

Find:    &lt;
Replace: <

Find:    &gt;
Replace: >

Migrate images

Regex for jetpack optimised images:

Find:    <img.*src=".+wp-content/uploads(.+)\?.+".*/>
Replace: ![todo](/assets/images$1)


Add Bootstrap 4

Pros and Cons

Jekyll on Github compared to Wordpress is:

  • faster: no database access, no programming language, only raw html and images
  • cheaper: you only pay for the domain name (~$10/year) instead of paying for a VPS $5/mo
  • safer: no login or admin backoffice, no field and no form, no .htaccess and not on-premise so there’s 0 security flaw
  • highly customizable: without being too complex to edit, Jekyll offers a quick way to extend its functionnalities
  • not bloated: I got sick of WP because of 5-10 sec page loads.. A quick look at the HTML source and some Lighthouse audits reveal a lot of useless JS+CSS
  • bootstrap friendly: most of the WP themes will break when used with BS. As Jekyll is built with simplicity in mind, adding BS will keep everything in order. This way, components (alert, popover, icons…) and utilities (grid, show/hide…) are available
  • focused on content: with Markdown (.md) based files, Jekyll focuses on content rather than on markup. It relies on much cleaner a source

But on the other hand, Wordpress is better for:

  • the setup: WP can be set up in 5-10 min, instead of 1-2 days for an extended Jekyll website
  • plugins: which are the reason of the bloat.. But for GA, GTM, SEO, RSS, code highlighting, etc. WP has some first-class and easy-to-install plugins, comparent to Jekyll where there’s a need of writing raw HTML/Liquid
  • the ecosystem and the community: WP has more experience, runs on more websites and has many big brands support
  • private drafts: drafts are open source on Jekyll, which is a pain in the a**
  • Images management: WP is really easy to use for images