DEV Community

Lennart
Lennart

Posted on • Originally published at lekoarts.de

Adding a Draft Feature to Gatsby

There are a lot of guides on the internet on how to add default values to your Gatsby schema, e.g. a draft entry in the frontmatter to hide posts that are still work-in-progress. However, all these solutions are kinda hacky, as they for example require you to use environment variables or even define the draft entry in every single frontmatter you have. Since Gatsby implemented its schema customization API there is an easy solution (and not hacky at all!) available. Most importantly: This quick tip is applicable to all data sources you have, not only markdown (and its frontmatter).

You can have a look at the codesandbox gatsby-draft-default-values to see the working code in a minimal example.

If you want to follow the example along, you can install the default blog starter by running gatsby new my-blog https://github.com/gatsbyjs/gatsby-starter-blog with gatsby-cli.

Setup

The default blog starter uses markdown for its content and you can use the so called frontmatter in markdown files to define additional data, such as e.g. a draft status (true or false). The goal is to define a default value for this draft status so that you don't have to define it in every markdown file but only in the ones you'd like to be a draft.

Add this to the existing gatsby-node.js file:

exports.createSchemaCustomization = ({ actions }) => {
  const { createTypes, createFieldExtension } = actions

  createFieldExtension({
    name: "defaultFalse",
    extend() {
      return {
        resolve(source, args, context, info) {
          if (source[info.fieldName] == null) {
            return false
          }
          return source[info.fieldName]
        },
      }
    },
  })

  createTypes(`
    type MarkdownRemark implements Node {
      frontmatter: Frontmatter
    }
    type Frontmatter {
      draft: Boolean @defaultFalse
    }
  `)
}
Enter fullscreen mode Exit fullscreen mode

In the createTypes function you have to define a nested type on the MarkdownRemark type (read Nested types for more info) to be able to type the draft field. On the draft field itself the custom extension is used as a directive. The directive allows you to reuse this action on other fields, too. In case you're using a CMS or other datasource than markdown you'll need to find and define your type (instead of MarkdownRemark) to have this working. I'd recommend using GraphiQL (localhost:8000/___graphql) if you're unsure about the names!

To be able to use the @defaultFalse directive, you need to define a custom extension with createFieldExtension. The source contains all fields from the frontmatter (in this case: title, description, date, and draft). info.fieldName is the name of the field you're applying the directive to – in this case draft. Fields that are not provided are null by default but because draft should be a boolean you need to return false in this case. If it's provided simply return the value.

Read the complete guide on Creating type definitions to get in-depth knowledge of how and why it works this way.

Usage

Now that the draft field is set up and defaults to false, you can go ahead and add a draft: true to the frontmatter of a blogpost.

---
title: "My Second Post!"
date: "2015-05-06T23:46:37.121Z"
draft: true
---
Enter fullscreen mode Exit fullscreen mode

When opening GraphiQL you also should be able to query the draft field now and filter by it. A query to list all markdown posts that are not a draft looks like:

query {
  allMarkdownRemark(filter: { frontmatter: { draft: { eq: false } } }) {
    nodes {
      frontmatter {
        title
        description
        date
        draft
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)