I put the folder where the article is stored in another location on my computer.
My folder directory design is like this:
|root
|---File directory A
|------Article A.md
|------Article B.md
|---File directory B
|------hello world.md
I want to create a corresponding category based on the name of the folder above.
Now I have pointed the path of gatsby-source-filesystem to root.
My query code is:
allDirectory(filter: {relativeDirectory: {eq: ""}}) {
edges {
node {
name
dir
}
}
}
Filtering is to prevent subdirectories.
const allCategory = []
_.each(result.data.allDirectory.edges, edge => {
if (_.get(edge, 'node.name') && _.get(edge, 'node.dir')) {
allCategory.push(edge.node)
}
})
allCategory.forEach(category => {
createPage({
path: `/category/${_.kebabCase(category.name)}`,
component: categoryTemplate,
context: {
name: category.name,
query: `/^${category.dir}${category.name}/`
}
})
})
Query article code:
query CategoryQuery($query: String!) {
allMarkdownRemark(filter: { fileAbsolutePath: { regx: $query } } ) {
edges {
node {
frontmatter {
title
}
fields {
slug
}
}
}
}
}
But I don't know how to group.
This is a query for the tag grouping, but it cannot be used for Category grouping because I don't know how to fill in "field"
allMarkdownRemark{
group(field: frontmatter___tags) {
fieldValue
totalCount
}
}
I tried Google many times, but there was no result, I can only come to Github to ask questions.
I am not a native English speaker, I am very sorry that this question may not be obvious.
Please help me, thank you all.
@mostearly let me start by saying two things. One, sorry for the late response, but with the holidays coming, time tends to be ohh so small to address so many things at once.
Two, you don't need to say your sorry, this community is based on people all around the world, which probably makes a portion of them not native English speakers.
You did a good job at exposing your question.
Now with that out of the way, i'm going to break my answer into smaller parts so that you'll pick up on it and either solve your issue, or point you in the right direction for the solution.
|gatsby-site(test_gatsby_grouping)
|root
|---ContentA(category folder)
|------ArticleA.md
|------ArticleB.md
|---ContentB(category folder)
|------index.md
gatsy-config.js file to to get the information from the root folder. Resulting in the following contents on the filemodule.exports = {
siteMetadata: {
title: `Gatsby Starter Blog`,
author: `Kyle Mathews`,
description: `A starter blog demonstrating what Gatsby can do.`,
siteUrl: `https://gatsby-starter-blog-demo.netlify.com/`,
social: {
twitter: `kylemathews`,
},
},
plugins: [
{
resolve:`gatsby-source-filesystem`,
options:{
path:`../root`, //<-root folder reference
name:`otherContent`
}
},
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/content/assets`,
name: `assets`,
},
},
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 590,
},
},
{
resolve: `gatsby-remark-responsive-iframe`,
options: {
wrapperStyle: `margin-bottom: 1.0725rem`,
},
},
`gatsby-remark-prismjs`,
`gatsby-remark-copy-linked-files`,
`gatsby-remark-smartypants`,
],
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-google-analytics`,
options: {
//trackingId: `ADD YOUR TRACKING ID HERE`,
},
},
`gatsby-plugin-feed`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `Gatsby Starter Blog`,
short_name: `GatsbyJS`,
start_url: `/`,
background_color: `#ffffff`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `content/assets/gatsby-icon.png`,
},
},
/* `gatsby-plugin-offline`, */
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-plugin-typography`,
options: {
pathToConfigModule: `src/utils/typography`,
},
},
],
}
gatsby-node.js file so that gatsby can pickup on the content and create the pages and get the categories. Resulting in the following contents on the file.const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)
const _ = require("lodash")
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
return graphql(
`
{
allMarkdownRemark(
sort: { fields: [frontmatter___date], order: DESC }limit: 1000) {
edges {
node {
fields {
slug
}
frontmatter {
title
path
category
}
}
}
}
}
`
).then(result=>{
if (result.errors) {
result.errors.forEach(e => console.error(e.toString()))
return Promise.reject(result.errors)
}
const blogPost = path.resolve(`./src/templates/blog-post.js`)
// Create blog posts pages.
const posts = result.data.allMarkdownRemark.edges
posts.forEach((post, index) => {
const previous =
index === posts.length - 1 ? null : posts[index + 1].node
const next = index === 0 ? null : posts[index - 1].node
createPage({
path: post.node.fields.slug,
component: blogPost,
context: {
slug: post.node.fields.slug,
previous,
next,
},
})
})
})
.then(()=>{
return graphql(`
{
allDirectory(filter: {relativeDirectory: {eq: ""}}){
edges{
node{
id
name
}
}
}
}
`)
}).then(result=>{
if (result.errors) {
result.errors.forEach(e => console.error(e.toString()))
return Promise.reject(result.errors)
}
const categoriesTemplate= path.resolve('./src/templates/categories.js')
const categoryList= result.data.allDirectory.edges
let categories=[]
_.each(categoryList,edge=>{
if (_.get(edge,"node.name")){
categories = categories.concat(edge.node.name)
}
})
categories=_.uniq(categories)
categories.forEach(item=>{
createPage({
path: `/categories/${_.kebabCase(item)}/`,
component:categoriesTemplate,
context:{
cat:item
},
})
})
})
}
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode })
createNodeField({
name: `slug`,
node,
value,
})
}
}
src/templates/categories.js, with the following contents.import React from 'react'
import { Link, graphql } from 'gatsby'
const Category = ({ pageContext, data }) => {
const { cat } = pageContext
const { edges, totalCount } = data.allMarkdownRemark
const catHeader = `${totalCount} post${
totalCount === 1 ? '' : 's'
} with category "${cat}"`
return (
<div>
<h1>{catHeader}</h1>
<ul>
{edges.map(({ node }) => {
const { path, title } = node.frontmatter
return (
<li key={path}>
<Link to={path}>{title}</Link>
</li>
)
})}
</ul>
<Link to="/category">All categories</Link>
</div>
)
}
export default Category
export const pageQuery = graphql`
query($cat: String) {
allMarkdownRemark(
limit: 2000
sort: { fields: [frontmatter___date], order: DESC }
filter: { frontmatter: { category: { in: [$cat] } } }
) {
totalCount
edges {
node {
frontmatter {
title
path
}
}
}
}
}
`
After you've cloned the repository i've set up in here and you install and run the site with gatsby develop. If you head onto http://localhost:8000/category/, you'll get the number of items by category, based on the folder. And also you'll be able to navigate through it and see the content based on the categories created.
Now regarding this part of your description in the issue.
allMarkdownRemark{
group(field: frontmatter___tags) {
fieldValue
totalCount
}
}
To my knowledge and i might be wrong about this, in order to get it to group by categories, not tags for instance.
What you had to do is to create a field called category in the .md files and then, when gatsby's transformer remark plugin is processing the files, it would see that a field exists and it will give you access to it in the form of something like this:
allMarkdownRemark{
group(field: frontmatter___category) {
fieldValue
totalCount
}
}
It is implemented in the repository i've mentioned, so that you could see that despite the folder you'll have as a category, you would need to create the field inside the file.
Sorry for the long response.
And i hope i could be helpfull in resolving your issue.
Feel free to provide some feedback.
Thanks for using Gatsby 👍
@jonniebigodes
Sorry, I didn't explain my purpose.
The classification by folder is mainly to reduce the mark of YAML in the MD file.
I used the WordPress blog program before, it can reduce my editing of the article information.
Now using static blogs, I need to mark the article information in the MD file, this makes me somewhat not adapted.
Is there a way to not mark it in the MD file?
Thank you!
@mostearly no, you did explain and on my comment to the best of my knowledge, to apply your approach you would have to inject the frontmatter category field in the md file. The path field can be removed from there and change the gatsby-node.js file to generate the paths without the need of that field. But in order to apply the grouping using that graphql query you would have to go that route. Otherwise you probably would have to take a diferent approach. Once again i might be wrong on this. And with that i'm going to keep this issue open to see if anyone has a diferent take on the subject.
Thanks for keeping this issue open, I've been running into similar problems and this discussion has been very helpful.
It seems that presently, creating a dedicated field in the frontmatter is the most straightforward solution, but I also feel like it _should_ be possible to programmatically create such a field based on the containing folder name, similar to how slugs for pages are usually added as an extra field within onCreateNode using the createNodeField API. Has anyone had any success with this?
As an aside, I'm not only using gatsby-transformer-remark in my project, but also gatsby-transformer-yaml, and I noticed that the yaml plugin actually creates nodes/"collections" based on folder names out of the box.
Put differently, where gatsby-transformer-remark only gives us allMarkdownRemark and markdownRemark to query for, gatsby-transformer-yaml gives us allContentAYaml and allContentBYaml without requiring any additional configuration. If this or a similar option existed for the remark plugin, too, it would be trivial to query only one category of content, and easy enough to generate a category field based on node.internal.type for grouping.
I haven't spent a lot of time looking at how both plugins differ in how they work, but I'm wondering if this capability would be easy enough to add to the remark plugin, too.
Hiya!
This issue has gone quiet. Spooky quiet. 👻
We get a lot of issues, so we currently close issues after 30 days of inactivity. It’s been at least 20 days since the last update here.
If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open!
Thanks for being a part of the Gatsby community! 💪💜
Hey again!
It’s been 30 days since anything happened on this issue, so our friendly neighborhood robot (that’s me!) is going to close it.
Please keep in mind that I’m only a robot, so if I’ve closed this issue in error, I’m HUMAN_EMOTION_SORRY. Please feel free to reopen this issue or create a new one if you need anything else.
Thanks again for being part of the Gatsby community!
@diondiondion Yes, you can create the required fields through actions.createNodeField. The explanation of the official documentation is also to create the required fields with this function. I used this function and the getNode function to supplement those Markdown documents that don't want to fill in YAML.
@mostearly Indeed. I'm not sure if there is enough interest in this feature being made available in Markdown Remark to re-open the issue. I think it would be great if the remark plugin came with the same folder-based functionality for collections as the Yaml plugin, it would probably make life easier for a lot of people.
Most helpful comment
@mostearly Indeed. I'm not sure if there is enough interest in this feature being made available in Markdown Remark to re-open the issue. I think it would be great if the remark plugin came with the same folder-based functionality for collections as the Yaml plugin, it would probably make life easier for a lot of people.