'gatsby multiple collection routes for multiple markdown folders
I have two markdown collection routes which I want to apply to two different sets of markdowns separated by subfolders.
My folder structure is as follows
appfolder
content
projects
project1.md
project2.md
article
article1.md
article2.md
src
pages
projects
{MarkdownRemark.frontmatter__slug}.js
articles
{MarkdownRemark.frontmatter__slug}.js
The content of projects/{MarkdownRemark.frontmatter__slug}.js is as follows
import React from 'react';
import Layout from "../../components/Layout";
import Nav from "../../components/Nav";
import PageHeader from "../../components/PageHeader";
import Footer from "../../components/Footer";
import SimpleReactLightbox from 'simple-react-lightbox'
import { graphql } from 'gatsby'
const ProjectPage = ({data}) => {
const fm = data.markdownRemark.frontmatter;
const html = data.markdownRemark.html;
return (
<SimpleReactLightbox>
<Layout pageTitle={fm.title}>
<Nav />
<PageHeader title={fm.title} />
<Footer />
</Layout>
</SimpleReactLightbox>
);
};
export const query = graphql`
query($id: String!) {
markdownRemark(id: { eq: $id },fileAbsolutePath: {regex: "/(projects)/" }) {
html
frontmatter {
slug
title
summary
icon
}
}
}
`
export default ProjectPage;
But GraphiQL shows that the pages are generated for all md files. How do I restrict each collection route to respective subfolder.
Solution 1:[1]
Think your issues falls at fileAbsolutePath for the regex.
Change (projects) to just projects
Solution 2:[2]
In that cases, I think the easiest approach is adding a "key" value in your frontmatter to make the filter. For example:
---
key: article
title: Test Title
anotherField: Another field value
---
The body of the markdown
Note: change key: article for key: projects when needed
Then, in your GraphQL query use the filter with something like:
export const query = graphql`
query($id: String!) {
markdownRemark(id: { eq: $id }, filter: { frontmatter: { key: { eq: "article" },
}
},, ) {
html
frontmatter {
slug
title
summary
icon
}
}
}
`
Tweak it as you need and check the availability of the filters in the localhost:8000/___graphql playground.
Solution 3:[3]
I just ran into the same problem. It seems like there are no ready-made solutions for your current organization of src/pages. But after running through the discussions on Gatsby, I found there are some workarounds, though I think it's a bit inconvenient.
Like this comment said:
If your source nodes contain something like
category: "article" | "blog", you could generate separate routes with file nested incategorydirectory like/{SourceNode.category}/{SourceNode.slug}.tsx.If your source node does not contain such a category field, then you can append it to the nodes in onCreateNode hook, or create entirely new nodes for your purposes
In your case, if you can add a category field to the frontmatter in your .md files, you can change your organization of src to
appfolder
content
projects
project1.md
project2.md
article
article1.md
article2.md
src
templates
project-template.js
article-template.js
pages
{MarkdownRemark.frontmatter__category}
{MarkdownRemark.frontmatter__slug}.js
Then projects/{MarkdownRemark.frontmatter__slug}.js goes to templates/project-template.js and the article one is similar.
Now in your {MarkdownRemark.frontmatter__slug}.js file, you can forward the data queried by GraphQL to the corresponding template.
// {MarkdownRemark.frontmatter__slug}.js
const GeneratedPage = ({ data }) => {
const templates = {
project: <ProjectTemplate data={data} />,
article: <ArticleTemplate data={data} />,
};
return templates[data.MarkdownRemark.frontmatter.category];
};
If it's not possible to add the category field into the .md file, make use of the createNodeField API to programmatically add it to MarkdownRemark nodes in gatsby-node.js. It maybe something like this:
// gatsby-node.js
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions;
if (node.internal.type === `MarkdownRemark`) {
const value = ...; // something mapping the directory of node to certain catecory
createNodeField({
name: 'category',
node,
value,
});
}
};
Hope this can be helpful to you.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | DᴀʀᴛʜVᴀᴅᴇʀ |
| Solution 2 | Ferran Buireu |
| Solution 3 | Kento |
