Skip to content

Instantly share code, notes, and snippets.

@SimeonGriggs
Last active July 14, 2023 14:42
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SimeonGriggs/b1a4281cb6af43b0fc6cc3627fe3092a to your computer and use it in GitHub Desktop.
Save SimeonGriggs/b1a4281cb6af43b0fc6cc3627fe3092a to your computer and use it in GitHub Desktop.
Sanity.io: A slug field with a prefix based on a "category" reference's slug
import {SlugSourceFn, SlugifierFn, defineField, defineType} from 'sanity'
import get from 'lodash/get'
// Fetch the category's slug – if present – and append the post's title
const handleSlugSource: SlugSourceFn = async (doc, context) => {
const categoryRef = get(doc, `category._ref`)
if (categoryRef) {
const client = context.getClient({apiVersion: `2023-07-01`})
const categorySlug = await client.fetch(`*[_id == $id][0].slug.current`, {id: categoryRef})
if (categorySlug) {
return `${categorySlug}/${doc.title}`
}
}
return String(doc.title)
}
// DIY basic slugifier
const slugify = (source: string) => source.toLowerCase().replace(/\s+/g, `-`)
// Default slugifier would replace the `/` inserted above with a `-`
const handleSlugify: SlugifierFn = (source, schemaType, context) => {
return `/` + source.split(`/`).map(slugify).join(`/`)
}
// Example schema with a slug field
// which will take the category's slug – if present – and append the post's title
export const postType = defineType({
name: 'post',
title: 'Post',
type: 'document',
fields: [
defineField({
name: 'title',
type: 'string',
}),
defineField({
name: 'slug',
type: 'slug',
options: {
source: handleSlugSource,
slugify: handleSlugify
},
// In this validation rule, we check that the slug starts with the category's slug
// You would need to update this logic if "category" was also required
validation: rule => rule.custom(async (value, context) => {
if (!value?.current) {
return `Slug is a required field`
}
const categoryRef = get(context.document, `category._ref`)
if (categoryRef) {
const client = context.getClient({apiVersion: `2023-07-01`})
const categorySlug = await client.fetch(`*[_id == $id][0].slug.current`, {id: categoryRef})
if (categorySlug && !value.current.startsWith(`/${categorySlug}/`)) {
return `Slug must start with the category's slug`
}
} else if (!value.current.startsWith(`/`)) {
return `Slug must start with a /`
}
return true
})
}),
defineField({
name: 'category',
type: 'reference', to: {type: 'category'}
}),
],
preview: {
select: {
title: 'title',
subtitle: 'slug.current',
},
},
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment