Mathias Riis Sorensen
Mathias Riis Sorensen

Reputation: 850

GraphQL query filter with dynamic pages

I'm creating dynamic pages for all my categories. Those are stored within our CMS from GraphCMS, so adding new categories would generate a new category button as well as a page.

On the dynamically generated page, I would like to show all relevant posts with the associated category.

I'm using GatsbyJS and GraphQL queries to fetch the data from GraphCMS.

This is the Category query in my gatsby-node.js file:

categories: allGraphCmsCategory {
          nodes {
            title
            slug
            description
            id
          }
        }

This is how I create the pages. The code is within the gatsby-node.js:

data.categories.nodes.forEach(category => {
    createPage({
      component: path.resolve("./src/templates/category-page.tsx"),
      context: {
        category,
      },
      path: `/articles/categories/${category.slug}`,
    })
  })

This is the template file for the category page named "category-page.tsx":

import React from "react"
import styled from "styled-components"
import { H1, BodyMain } from "../components/styles/TextStyles"

export default function CategoryPageTemplate({ pageContext: { category } }) {
  return (
    <Wrapper>
      <HeaderWrapper>
        <TextWrapper>
          <TitleWrapper>{category.title}</TitleWrapper>
          <DescriptionWrapper>{category.description}</DescriptionWrapper>
        </TextWrapper>
      </HeaderWrapper>
    </Wrapper>
  )
}
const Wrapper = styled.div``

const HeaderWrapper = styled.div`
  min-height: 250px;
  display: grid;
  justify-content: center;
  align-items: center;
  padding: 30px;
`

const TextWrapper = styled.div`
  display: grid;
  grid-gap: 1rem;
  text-align: center;
`

const TitleWrapper = styled(H1)`
  padding: 0.2rem;
  font-weight: 900;
  background: -webkit-linear-gradient(left, #7230ce, #3E16BB)};
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
`

const DescriptionWrapper = styled(BodyMain)``

This is my query for post:

allGraphCmsPost(sort: { fields: date, order: ASC }) {
          edges {
            nextPost: next {
              slug
              title
            }
            page: node {
              id
              author {
                id
                name
                title
              }
              content {
                markdownNode {
                  childMdx {
                    body
                  }
                }
              }
              date: formattedDate
              excerpt
              seo {
                description
                image {
                  url
                }
                keywords
                title
              }
              slug
              title
            }
            previousPost: previous {
              slug
              title
            }
          }
        }

Can you guide me in the right direction? I'm thinking about GraphQL query with filtering on, but I'm not certain how I would accomplish that when the pages has to be dynamic.

Upvotes: 0

Views: 1277

Answers (1)

Ferran Buireu
Ferran Buireu

Reputation: 29320

You have two options. You can modify the category node to add the related posts by customizing the Graphql schema or you can make two separate queries and filter for the category.

There's not enough information about the data structure to provide a solid answer to modify the GraphQL schema so I will focus on the second approach.

import React from "react"
import styled from "styled-components"
import { H1, BodyMain } from "../components/styles/TextStyles"

export default function CategoryPageTemplate({ pageContext: { category }, data }) {
    const filteredPosts = data.allMarkdownRemark.edges.filter(({ node }) =>{
       node.frontmatter.category == category.title
    });

  return (
    <Wrapper>
      <HeaderWrapper>
        <TextWrapper>
          <TitleWrapper>{category.title}</TitleWrapper>
          <DescriptionWrapper>{category.description}</DescriptionWrapper>
        </TextWrapper>
      </HeaderWrapper>
    </Wrapper>
  )
}
const Wrapper = styled.div``

   // omitted the styles to avoid a huge answer

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

Note: I've assumed a default markdown data structure, adapt it to your needs if it doesn't match yours.

The idea is to create a new query to get all posts and there, the information will be holded by data (destructured from props.data), then, filter them with the title of the category (assuming that the posts will have a category field, it must have one).

Upvotes: 1

Related Questions