Last active
October 16, 2021 09:46
-
-
Save ajmalafif/2eebf40e6343dbe5963d279a89987eaf to your computer and use it in GitHub Desktop.
Related Reviews/Posts with Sanity.io and GatsbyJS 3.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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