Seperating posts and pages in Gatsby

You’ll see from the docs that you list the source of your files in the gatsby-config.php file in the options for the remark plugin. https://www.gatsbyjs.org/packages/gatsby-transformer-remark/

If you kicked off with the starter blog it will be setup to source the markdown files from the pages folder. I liked having my posts in a seperate folder for better organisation. So I make a folder next to pages for posts.

To add more source locations, we just need to duplicate the plugin config in gatsby-config.php.

{
 resolve: `gatsby-source-filesystem`,
 options: {
   name: `pages`,
   path: `${__dirname}/src/pages/`,
 },
},
{
 resolve: `gatsby-source-filesystem`,
 options: {
   path: `${__dirname}/src/posts`,
   name: 'posts',
 },
},

So just copy the config then change the second one to point to your new location. Then any markdown pages placed in the posts or pages folder will be brought in.

You need to restart Gatsby for these changes to take effect.

Now here’s the really important bit. All of these will come in to the same source. That’s fine if you want all your markdown pages to behave as posts, but chances are, you don’t.

Seperate templates

I wanted to have a seperate templates for my post and pages. So I needed a way to do this. As I see it, there are two ways.

First would be to use GraphQL twice to create a filter for posts and another request for pages. But that seemed like a lot of code duplication so I went for option two which was to use a frontmatter - “layout: page”. How you would select a layout in Jekyll.

So on my pages I added that to the front matter at the top. Then in my createpages function in gatsby-node.js, I used that to select the template.

if( post.node.frontmatter.layout === 'page') {
  template = pageTemplate;
}

If you used the stater blog template, you’ll see the post template var at the top. The pageTemplate var I’ve set above is a dup of that, but linking to the page template, like this:

const postTemplate = path.resolve('./src/templates/blog-post.js')
const pageTemplate = path.resolve('./src/templates/page.js')
---
title: About
layout: page
---

You need to add the layout option to the GraphQL query to to make it available, add it under the frontmatter heading as so:

{
  allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }, limit: 1000) {
    edges {
      node {
        fields {
          slug
        }
        frontmatter {
          title
          layout
        }
      }
    }
  }
}

I’ll link to a gist at the end of the whole thing so you get see it in context.

Seperate Queries

So now you’ve got seperate templates, you’ll need to do some filtering on the blog roll.

This is the GraphQL query that comes with the blog stater on the index.js page:

export const pageQuery = graphql`
  query IndexQuery {
    site {
      siteMetadata {
        title
      }
    }
    allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
      edges {
        node {
          excerpt
          fields {
            slug
          }
          frontmatter {
            date(formatString: "DD MMMM, YYYY")
            title
          }
        }
      }
    }
  }
`

We want to filter that data to exclude the pages so it only list the blog posts.

I added this filter so it only includes posts from the posts folder.

filter: {
   id: { regex: "/posts/" }
}) {

The whole thing

query IndexQuery {
    site {
      siteMetadata {
        title
      }
    }
    allMarkdownRemark(
      sort: {fields: [frontmatter___date],order: DESC},
      filter: {
        id: { regex: "/posts/" }
      }) {
      edges {
        node {
          excerpt
          fields {
            slug
          }
          frontmatter {
            date(formatString: "DD MMMM, YYYY")
            title
          }
        }
      }
    }
  }

That’s it.

As promised here’s that gist, to help you see it all in context.

https://gist.github.com/Zackio/a1ccfa647fb3a99766fc17f7dd1e31e5


Kyle Mathews

Written by Zack Allnutt who works as a freelancer in the UK, building useful things in PHP and Javascript.