Skip to content

Instantly share code, notes, and snippets.

@ajmalafif
Last active October 16, 2021 09:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ajmalafif/2eebf40e6343dbe5963d279a89987eaf to your computer and use it in GitHub Desktop.
Save ajmalafif/2eebf40e6343dbe5963d279a89987eaf to your computer and use it in GitHub Desktop.
Related Reviews/Posts with Sanity.io and GatsbyJS 3.0
//Hook into the createSchemaCustomization API
//This hook runs after all our nodes have been created
exports.createSchemaCustomization = ({ actions, schema }) => {
//The createTypes action allows us to create custom types
//and modify existing ones
const { createTypes } = actions
// Create our schema customizations
const typeDefs = [
// Replace "SanityReview" with your _typename of your post type
"type SanityReview implements Node { related: [SanityReview] }",
schema.buildObjectType({
name: "SanityReview",
fields: {
related: {
type: "[SanityReview]",
//The resolve field is called when your page query looks for related posts
//Here we can query our data for posts we deem 'related'
//Exactly how you do this is up to you
//I'm querying purely by category
//But you could pull every single post and do a text match if you really wanted
//(note that might slow down your build time a bit)
//You could even query an external API if you needed
resolve: async (source, args, context, info) => {
//source is the current (post) object
//context provides some methods to interact with the data store
//Map a simple array of category IDs from our source object
//In my data each category in the array is an object with a _id field
//We're just flattening that to an array of those _id values
//E.g. categories = ["1234", "4567", "4534"]
const categories = source.categories.map((c) => c._id)
//If this post has no categories, return an empty array
if (!categories.length) return ["uncategorized"]
//Query the data store for posts in our target categories
const post = await context.nodeModel.runQuery({
query: {
filter: {
//We're filtering for categories that are sharedby our source node
categories: { elemMatch: { _id: { in: categories } } },
//Dont forget to exclude the current post node!
_id: { ne: source._id },
},
},
//Change this to match the data type of your post
//This will vary depending on how you source content
type: "SanityReview",
})
//Gatsby gets unhappy if we return "null" here
//So check the result and either return an array of post,
//or an empty array
return post && post.length ? post : []
},
},
},
}),
]
createTypes(typeDefs)
}
// studio / schemas / documents / review.js
import {format} from 'date-fns'
export default {
name: 'review',
type: 'document',
title: 'Reviews',
fields: [
{
name: 'title',
type: 'string',
title: 'Title',
description: 'Titles should be catchy, descriptive, and not too long'
},
{
name: 'slug',
type: 'slug',
title: 'Slug',
description: 'Some frontends will require a slug to be set to be able to show the post',
options: {
source: 'title',
maxLength: 96
}
},
{
name: 'publishedAt',
type: 'datetime',
title: 'Published at',
description: 'This can be used to schedule post for publishing'
},
{
name: 'mainImage',
type: 'mainImage',
title: 'Main image'
},
{
name: 'excerpt',
type: 'excerptPortableText',
title: 'Excerpt',
description:
'This ends up on summary pages, on Google, when people share your post in social media.'
},
{
name: 'authors',
title: 'Authors',
type: 'array',
of: [
{
type: 'authorReference'
}
]
},
{
title: 'Tag',
name: 'tag',
type: 'array',
of: [{type: 'string'}],
options: {
layout: 'tags'
}
},
{
name: 'categories',
type: 'array',
title: 'Review Category',
of: [
{
type: 'reference',
to: [
{
title: 'Category',
type: 'categoryReview'
}
]
}
]
},
{
name: 'reviews',
type: 'array',
title: 'Collection of Reviews',
of: [
{
type: 'reviewText'
}
]
}
],
orderings: [
{
name: 'publishingDateAsc',
title: 'Publishing date new–>old',
by: [
{
field: 'publishedAt',
direction: 'asc'
},
{
field: 'title',
direction: 'asc'
}
]
},
{
name: 'publishingDateDesc',
title: 'Publishing date old->new',
by: [
{
field: 'publishedAt',
direction: 'desc'
},
{
field: 'title',
direction: 'asc'
}
]
}
],
preview: {
select: {
title: 'title',
publishedAt: 'publishedAt',
slug: 'slug',
media: 'mainImage'
},
prepare({ title = 'No title', publishedAt, slug = {}, media }) {
const path = `/${slug.current}/`
return {
title,
media,
subtitle: publishedAt ? path : 'Missing publishing date'
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment