
Filter Draft Posts
Introduction
Today we are going to be adding a draft
property to our blog posts. This will allow us to work on a post and keep it from showing. There are probably several ways you could use this but I am doing it so that I can have someone else review my posts as a pull request in Github. Once the review is good we can push an update to set the flag to false and approve it. I am using DevOps so, when the PR is approved, that fires off an action in GitHub that will build and deploy the code to our site. Another benefit is that you can work on several posts at the same time. I like to schedule these out a bit so that there are always 2 or 3 in the pipeline at various stages of done.
Code
To implement this we need to add a property to our schema. In astro we do this in the config.ts
file. We are going to add a property called draft
that is a boolean. When true
it will be excluded from display on the website blog page. When false
the post will be shown.
Schema update
We need to add the line draft: z.boolean().optional()
in the schema
object.
Here is my config.ts
blog schema.
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content',
// Type-check frontmatter using a schema
schema: z.object({
title: z.string(),
description: z.string(),
// Transform string to Date object
pubDate: z.date(),
updatedDate: z.coerce.date().optional(),
preview: z.string(),
draft: z.boolean().optional()
}),
});
export const collections = { blog };
I chose to make this an optional parameter because Frontmatter CMS will remove the property from the front matter metadata when it is false.
Filter the Collection
Now that we have a property in the schema to use we need to use it in the function that fetches our blog posts. In astro, this can be found in /src/pages/blog/index.astro
. There is a constant called posts
that we will be modifying. We need to filter the posts based on the new draft
property.
const posts = (await getCollection("blog")).sort(
(a, b) => a.data.pubDate.valueOf() - b.data.pubDate.valueOf()
).filter(post => !!post.data.draft);
All we did here was add a call to filter()
. JavaScript supports function chaining so we can add .filter(post => !!post.data.draft)
to the end of the code we already had to fetch the posts. How nice! I am also using another JS oddity with !!
. You may be familiar with the !
operator as the logical “not”. When we use it twice we get a way to derive the “truthyness” of a value. Remember earlier when I said we were making this an optional property? That means that it may or not be present. In JS, this usually means the property will return undefined
. By using !!
we can turn it into a boolean value. In fact, undefined
, null
, 0, -0, NaN
, empty strings (''
) and false
are all “falsy” and will return false
. This is important because we are not going to have this present when a post is not in draft status (it will be undefined
).