DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for Publish Posts After a Date in Gatsby
Steven Mercatante
Steven Mercatante

Posted on • Originally published at stevenmercatante.com

Publish Posts After a Date in Gatsby


This post was originally published at stevemerc.com


I like writing articles ahead of time and only have them listed on my site based on whether the current date is greater than or equal to the article's date attribute. This means I get to write a bunch of content at once, but release it over time so there's a constant stream of new material on my site without having to rush to write it the night before.

Note: This lesson builds upon my previous Add a Published Field to Your Gatsby Posts to Control Their Visibility article.

The Solution

First, make sure your article/post/whatever has a date attribute in its frontmatter. For example, here's this post's frontmatter:

---
title: Publish Posts Based After a Date in Gatsby
date: '2019-10-08'
published: true
---

I'm already filtering my query to check the article's published attribute, so I need to add an additional check against its date. Let's add a filter that only returns articles whose date is less than or equal to the current date.

query AllArticles($currentDate: Date!) {
  allMdx(
    filter: {
      frontmatter: { published: { eq: true }, date: { lte: $currentDate } }
    }
    sort: { fields: [frontmatter___date], order: DESC }
  ) {
    edges {
      node {
        fields {
          slug
        }
        frontmatter {
          date(formatString: "MMMM DD, YYYY")
          title
        }
      }
    }
  }
}

But now we've gotta pass in that $currentDate variable, so open up your gatsby-node.js file and add the following:

// gatsby-node.js

exports.onCreatePage = ({ page, actions }) => {
  const { createPage, deletePage } = actions
  deletePage(page)
  createPage({
    ...page,
    context: {
      ...page.context,
      currentDate: getCurrentDate(),
    },
  })
}

onCreatePage is provided by Gatsby and is called whenever new pages are created. By overriding it here, we can pass additional data (currentDate) via its context object that'll be made available to all downstream components.

Here's the getCurrentDate implementation:

// gatsby-node.js

/**
 * Returns the current date in YYYY-MM-DD format
 */
function getCurrentDate() {
  const d = new Date()

  let month = (d.getMonth() + 1).toString()
  if (month.length < 2) {
    month = `0${month}`
  }

  let day = d.getDate().toString()
  if (day.length < 2) {
    day = `0${day}`
  }

  return `${d.getFullYear()}-${month}-${day}`
}

One More Thing...

In my Add Previous and Next Article Buttons in Gatsby article I show how to add "Previous Article" and "Next Article" buttons that depend on the published flag. For this date filtering, I needed to update this to account for the date constraint, so posts that are set to be released in the future don't appear in the pagination links before they're ready.

// gatsby-node.js

const publishedPosts = posts
  .filter(post => {
    return (
      post.node.frontmatter.published === true &&
      new Date(post.node.frontmatter.date) <= new Date(getCurrentDate())
    )
  })
  .reduce((acc, post) => {
    acc[post.node.fields.slug] = post
    return acc
  }, {})

Wrapping Up

With this new logic in place, I can write as much content as I want and set it to publish on a certain date. The only thing I need to do is rebuild and deploy my site (I'm looking for a way to automate this...)

πŸ‘‹ Enjoyed this post?

Join my newsletter and follow me on Twitter @mercatante for more content like this.

Top comments (0)

An Animated Guide to Node.js Event Lop

Node.js doesn’t stop from running other operations because of Libuv, a C++ library responsible for the event loop and asynchronously handling tasks such as network requests, DNS resolution, file system operations, data encryption, etc.

What happens under the hood when Node.js works on tasks such as database queries? We will explore it by following this piece of code step by step.