I'm using Netlify CMS on a gatsby site. I used the netlify CMS relation widget on my post collection to reference the title field of my author collection, so...
- {label: "Author", name: "author", widget: "relation", collection: "authors", searchFields: ["title", "firstName", "lastName"], valueField: "title"}
That works well but when I do a query in my GraphiQL window the only available field is author, with a single string, how do I access all the frontmatter of a particular author?
For that reason, Netlify CMS is made to be community-driven, and has never been locked to the Netlify platform (despite the name). With this in mind, you can: Use Netlify CMS without Netlify and deploy your site where you always have, hooking up your own CI, site hosting, CDN, etc.
Netlify CMS is not a true headless CMS as it doesn't expose any API for scalable content delivery.
The first file, admin/index. html , is the entry point for the Netlify CMS admin interface. This means that users navigate to yoursite.com/admin/ to access it. On the code side, it's a basic HTML starter page that loads the Netlify CMS JavaScript file.
Making the connection in Netlify turns out to just be the first step. Then you need to configure your gatsby-node.js file to make those relationships on build. The end result allows you to make a query on the posts that has a nested author. Here's the whole setup.
First the netlifyCMS config.yml which I have in static/admin
backend:
name: git-gateway
branch: development
media_folder: "static/images/uploads" # Media files will be stored in the repo under static/images/uploads
public_folder: "/images/uploads"
collections:
- name: "blog" # Used in routes, e.g., /admin/collections/blog
label: "Blog" # Used in the UI
folder: "src/pages/blog/posts" # The path to the folder where the documents are stored
create: true # Allow users to create new documents in this collection
slug: "{{year}}-{{month}}-{{day}}-{{slug}}" # Filename template, e.g., YYYY-MM-DD-title.md
fields: # The fields for each document, usually in front matter
- {label: "Layout", name: "layout", widget: "hidden", default: "blog"}
- {label: "Author", name: "author", widget: "relation", collection: "authors", searchFields: ["title", "firstName", "lastName"], valueField: "title"}
- {label: "Title", name: "title", widget: "string"}
- {label: "Publish Date", name: "date", widget: "datetime"}
- {label: "Featured Image", name: "thumbnail", widget: "image"}
- {label: "Body", name: "body", widget: "markdown"}
- name: "authors"
label: "Authors"
folder: "src/authors"
create: true
slug: "{{slug}}"
fields:
- {label: "Layout", name: "layout", widget: "hidden", default: "author"}
- {label: "Full Name", name: "title", widget: "string"}
- {label: "First Name", name: "firstName", widget: "string"}
- {label: "Last Name", name: "lastName", widget: "string"}
- {label: "Position", name: "position", widget: "string"}
- {label: "Profile Picture", name: "profilePicture", widget: "image"}
- {label: "Email", name: "email", widget: "string"}
Then at the bottom of my gatsby-node.js file.
exports.sourceNodes = ({ boundActionCreators, getNodes, getNode }) => {
const { createNodeField } = boundActionCreators;
const postsOfAuthors = {};
// iterate thorugh all markdown nodes to link books to author
// and build author index
const markdownNodes = getNodes()
.filter(node => node.internal.type === "MarkdownRemark")
.forEach(node => {
if (node.frontmatter.author) {
const authorNode = getNodes().find(
node2 =>
node2.internal.type === "MarkdownRemark" &&
node2.frontmatter.title === node.frontmatter.author
);
if (authorNode) {
createNodeField({
node,
name: "author",
value: authorNode.id,
});
// if it's first time for this author init empty array for his posts
if (!(authorNode.id in postsOfAuthors)) {
postsOfAuthors[authorNode.id] = [];
}
// add book to this author
postsOfAuthors[authorNode.id].push(node.id);
}
}
});
Object.entries(postsOfAuthors).forEach(([authorNodeId, postIds]) => {
createNodeField({
node: getNode(authorNodeId),
name: "posts",
value: postIds,
});
});
};
And lastly in gastby-config.js you need to add the mapping.
mapping: {
"MarkdownRemark.fields.author": "MarkdownRemark",
"MarkdownRemark.fields.posts": "MarkdownRemark",
}
Which gives you the ability to make a query like tis...
query AllPosts {
allMarkdownRemark (
filter: { fileAbsolutePath: {regex : "\/posts/"} },
sort: {fields: [frontmatter___date], order: DESC}
){
edges {
node {
fields {
author {
fields {
slug
}
frontmatter {
title
firstName
lastName
profilePicture
}
}
slug
}
frontmatter {
title
date(formatString:"MMM DD 'YY")
thumbnail
layout
}
excerpt
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With