A close-up of slightly out-of-focus monthly planner printed on a white paper.
Photo by Eric Rothermel on Unsplash

Caution!

This is an old post. Information here may be out-dated, or the post may re­flect opin­ions or be­liefs I no longer share.

This will be a short one, mainly for my own fu­ture ref­er­ence and for oth­ers mov­ing to eleventy and fac­ing this is­sue. You’ll no­tice this is my third post on eleventy in the past month, and I have no re­grets. I en­joy us­ing it.

Let’s get to it.

What are we try­ing to fix?

I have a bunch of blog posts in a di­rec­tory named _posts, each of which has a YAML front-mat­ter. If this set up sounds fa­mil­iar to you, it’s be­cause I moved from Jekyll.

Each blog post has a draft prop­erty, which takes a boolean value: true or false.

Whether you use a cus­tom col­lec­tion or the col­lec­tions built by eleventy us­ing the tags front-mat­ter — one thing it does­n’t do out of the box is skip build­ing posts which have a draft value set to true.

This ac­tu­ally makes sense. It is not blog-aware like Jekyll is.

Unfortunately, this also means any­one can view such pages/​posts even on a pub­lished site, if they are able to guess the perma­link for a draft post or if you for­get to set a meta tag for search en­gines to not in­dex the draft pages or posts.

A straight­for­ward so­lu­tion is to just move draft posts to a _drafts di­rec­tory, and add it to your .eleventyignore dot file.

If that works for you, great.

I use Forestry and not only did I want a more CMS-friendly so­lu­tion, but also the abil­ity to see all my draft posts on the de­vel­op­ment and stag­ing en­vi­ron­ments, but not pro­duc­tion.

There’s a clean so­lu­tion to this. 🙂

Tell me more. What’s the fix?

@11ty/eleventy, in its 0.11.0 re­lease, fea­tures an eleven­ty­Com­puted prop­erty which can be set us­ing a di­rec­tory data file, among other op­tions.

It al­lows you to dy­nam­i­cally set front-mat­ter val­ues at build-time. Eleventy com­putes them how you tell it to. Makes sense?

Creating a _posts.11tydata.js file un­der the _posts di­rec­tory, we can con­trol the front-mat­ter data for all of the files in this di­rec­tory.

We want to spec­ify a front-mat­ter of permalink: false where draft is true. When a col­lec­tion item is not a draft, we want to re­turn the same permalink value we’d have set in the lay­out files. In my case, I use Liquid, so the vari­ables get parsed by Liquid.

// _posts.11tydata.js
module.exports = {
eleventyComputed: {
permalink: data => {
let postPermalink =
"/blog/{{ page.date | date: '%Y/%m/%d' }}/{{ slug }}/";

if (process.env.ELEVENTY_ENV !== "production") return postPermalink;
else return data.draft ? false : postPermalink;
}
}
};

Being able to change the perma­link us­ing com­puted prop­er­ties is a spe­cial use-case. All other eleventy prop­er­ties can­not be over­rid­den like this, al­though you can still set front mat­ter for any of your own prop­er­ties freely.

The data vari­able is passed on by eleventy and in­cludes the front-mat­ter data for us to use, so we can use data.draft to check the draft sta­tus of each col­lec­tion item, in this case, a blog post.


And there you have it. 🤩

You can use this for any other col­lec­tion just as eas­ily. If you’d like to con­trol all items built by eleventy, use a Global Data File.

Zach re­leased the 0.11.0 ver­sion a cou­ple of days ago. Go ahead, up­date, and use com­puted data if you want to! 👍


Update (2020-05-16): You could ac­tu­ally just re­turn the perma­link from the front-mat­ter it­self! This al­lows you to use a global data file with­out re­peat­ing your perma­link struc­ture from your tem­plates. It would be like so:

// _posts.11tydata.js
module.exports = {
eleventyComputed: {
permalink: data => {
if (process.env.ELEVENTY_ENV !== "production") return data.permalink;
else return data.draft ? false : data.permalink;
}
}
};

I have im­ple­mented the same in my Smix Eleventy Starter.