Validating unique slugs with parent pages in Sanity hierarchical structure
Looking at your code, I can see the issue. You're trying to use custom validation on the slug field, but Sanity has a specific isUnique option for slug fields that should be used instead. The built-in uniqueness check is still running and causing the error.
Here's how to fix it:
Create a separate isUnique function:
// lib/isUniqueSlugWithParent.js
export async function isUniqueSlugWithParent(slug, context) {
const { document, getClient } = context;
const client = getClient({ apiVersion: '2025-02-19' });
const id = document?._id;
const parentRef = document?.parentPage?._ref;
// If no slug or no ID, consider it valid
if (!slug?.current || !id) {
return true;
}
// Remove draft prefix if present
const publishedId = id.replace(/^drafts\./, '');
// Check if any OTHER document has the same slug + parent combination
const query = `count(*[
_type == "pillar" &&
slug.current == $slug &&
parentPage._ref == $parentRef &&
!(_id in [$id, $draftId])
])`;
const params = {
slug: slug.current,
parentRef: parentRef,
id: publishedId,
draftId: `drafts.${publishedId}`
};
const count = await client.fetch(query, params);
return count === 0; // Return true if unique (count is 0)
}Update your schema to use the isUnique option:
import { isUniqueSlugWithParent } from '../lib/isUniqueSlugWithParent';
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'name',
slugify: (input) =>
input
.toLowerCase()
.replace(/\s+/g, '-')
.replace(/[&\/\\#,+()$~%.''":*?<>{}]/g, ''),
isUnique: isUniqueSlugWithParent // Use this instead of validation
}
// Remove the validation property entirely
},
{
name: 'parentPage',
title: 'Parent Page',
type: 'reference',
to: [{ type: 'pillar' }],
options: {
filter: '!defined(parentPage)',
},
}Key differences from your code:
- Use
isUniqueoption instead ofvalidation- The slug field has a specialisUniquecallback that overrides the default uniqueness check - The query checks the right thing - It looks for documents with the same slug AND same parent, excluding the current document (both draft and published versions)
- Return boolean directly -
isUniqueexpectstrue(unique) orfalse(not unique), unlike validation functions that can return error messages - Handle drafts properly - The query excludes both the published and draft versions of the current document
This will allow you to have multiple pages with slug "north-east" as long as they have different parent pages. The uniqueness is now scoped to the combination of slug + parent page.
Show original thread11 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.