Drafts are posts that are not yet ready to be published. Jekyll has built-in support for drafts. This is how it works.
Create a _drafts
folder at your site’s root, create a new post in that folder, and run jekyll serve
with the --drafts
switch. Your draft turns up at the top of your recent posts (or wherever you have set up new posts to appear on your site).
Problems and possible solutions
While this method is fine for locally previewing your drafts, what if you wanted to share a link to a friend or a co-worker, to ask for a review of a draft? Well, there are two problems with Jekyll drafts:
- If you host your Jekyll site on Github Pages, then you cannot use the
--drafts
switch. If you host elsewhere, you may be able to use a custom build command which includes--drafts
. Or you could pre-build your site with--drafts
locally, and push it. - Jekyll does not provide a page variable to determine if a page is a draft or not. You could add (say)
drafts: true
in the YAML front matter of the draft and usepage.drafts
to tailor your layout.
A quick Internet search suggested two solutions for public drafts: one, which builds on Jekyll’s tag or category feature and two, which builds on Jekyll’s collection feature.
Requirements
First I outlined my requirements:
- Publish drafts without using the
--drafts
switch. - Exclude drafts from
sitemap.xml
, the site search index (I use Algolia), and indexing by robots. - Exclude social sharing buttons, comments, related posts and links to next and previous posts from drafts.
- A link to a draft post must not change after it is published.
I adapted the latter solution to meet these requirements. Here is how it works.
Enable drafts as a collection
First of all, to enable the drafts
collection, I added the following to my _config.yml
:
collections:
drafts:
output: true
Now, if I create posts in the _drafts
folder at my site’s root, they will be published without requiring the --drafts
switch. That is because the collections
specification named drafts
overrides the default treatment of the _drafts
folder.
Set up defaults for drafts
Next, I set the following front matter defaults to all posts under the drafts
collection:
defaults:
- scope:
path: ""
type: drafts
values:
comments: false
share: false
related: false
sitemap: false #To hide from sitemap.xml
noindex: true #To hide from robots and crawlers
These defaults turn off commenting, social sharing buttons, related posts and inclusion in sitemap.xml
. Next, I used the page.noindex
variable to add a snippet in the header of each draft post as follows:
{% if page.noindex == true %}
<meta name="robots" content="noindex">
{% endif %}
This prevents robots from indexing draft posts. To exclude _drafts
from the site search index, I added the following (Algolia-specific setting) to the _config.yml
.
algolia:
files_to_exclude:
- _drafts/*.markdown
Maintaining draft links after publication
My posts use the following permalink format:
permalink: /:categories/:title/
I added the same permalink specification to the drafts
collection as follows:
collections:
drafts:
output: true
permalink: /:categories/:title/
Now, if I do not change the categories and title of my post, then the permalink would not change on publication. When I am ready to publish, I simple move the file from _drafts
to _posts
. That’s it!
The reason this works lies in the way Jekyll treats files in _posts
and files in collections (in our case, _drafts
). Files in _posts
are accessible in the variables site.posts
and site.categories
, but files in collections are not. But categories defined in a file, remain accessible as page.categories
whether the file is in _posts
or _drafts
.
That’s why the link doesn’t change on publication, but the file content appears in recent posts or a category index page, only when it is in _posts
(and not when it is still in _drafts
).
That concludes how I set up Jekyll drafts with shareable links.