Generate slug from multiple fields including nested references in Sanity V3
You can definitely generate a slug from multiple fields in Sanity V3! The source option in the slug field accepts a function that receives the document (doc) and can combine multiple fields, including nested references.
Here's how to modify your slug field to combine name, color, material, and style:
defineField({
name: 'slug',
title: 'Slug',
type: 'slug',
description: 'The slug for the product',
options: {
source: (doc) => {
// Start with the name
const parts = [doc.name];
// Add properties if they exist
if (doc.properties?.color) parts.push(doc.properties.color);
if (doc.properties?.material) parts.push(doc.properties.material);
if (doc.properties?.style) parts.push(doc.properties.style);
return parts.filter(Boolean).join(' ');
}
},
validation: (Rule) => Rule.required()
})However, there's an important caveat: Since color, material, and style are references to other documents, the source function will only receive the reference IDs (like {_ref: 'abc123'}), not the actual document data like the title or name of those referenced documents.
If you need to include the actual values from those referenced documents (like the color name), you have a few options:
Option 1: Use Custom Slugify Function
You can use the slugify option with access to more context through the slugify parameter. The context parameter contains document, parent, parentPath, and getClient:
options: {
source: 'name',
slugify: async (input, schemaType, context) => {
const { doc, getClient } = context;
const client = getClient({ apiVersion: '2024-01-01' });
// Fetch referenced documents
const refs = [
doc.properties?.color?._ref,
doc.properties?.material?._ref,
doc.properties?.style?._ref
].filter(Boolean);
if (refs.length === 0) return input.toLowerCase().replace(/\s+/g, '-');
const query = `*[_id in $refs]{_id, name}`;
const refDocs = await client.fetch(query, { refs });
// Build slug from actual names
const parts = [doc.name];
refDocs.forEach(refDoc => parts.push(refDoc.name));
return parts.join('-').toLowerCase().replace(/\s+/g, '-');
}
}Option 2: Store Values Directly (Simpler)
If you need the slug to include these values, consider storing the actual string values alongside the references:
{
name: 'colorName', // Store the actual name for slug generation
type: 'string',
hidden: true
}Option 3: Use a Sanity Function to Update on Publish
You could set up a Sanity Function that triggers on document changes and updates the slug based on referenced document data.
As mentioned in the Sanity documentation, you can definitely use multiple fields as a source by combining them in a function. The tricky part is working with references, which require dereferencing to get the actual values. The slugify option with context.getClient is your best bet for accessing referenced document data during slug generation.
Show original thread5 replies
Sanity ā Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.