Objetos reutilizables
Los objetos en schemas/objects/ son tipos que encapsulan un conjunto de campos relacionados y pueden incluirse en cualquier documento con una sola línea. No generan entradas propias en el Studio.
seo — Metadatos de SEO
Archivo: schemas/objects/SEOBase.ts
Tipo Sanity: "seo"
Export JS: seoBase
Agrupa los cuatro campos necesarios para controlar cómo aparece una página en buscadores y al compartirse en redes.
Campos
| Campo | Tipo | Restricción | Descripción |
|---|---|---|---|
metaTitle | string | máx. 60 caracteres | Título para Google. Si se omite, el front-end usa el title del documento. |
metaDescription | text | máx. 160 caracteres | Descripción para el snippet de búsqueda. |
ogImage | image | — | Imagen para Open Graph. Recomendado 1200×630 px. |
noIndex | boolean | false por defecto | Oculta la página de los motores de búsqueda. |
Las validaciones son warning, no error: el editor puede guardar aunque supere los límites, pero verá una advertencia en el Studio.
Código fuente
// schemas/objects/SEOBase.ts
import {defineField, defineType} from 'sanity'
export const seoBase = defineType({
name: 'seo',
title: 'SEO',
type: 'object',
fields: [
defineField({
name: 'metaTitle',
title: 'Meta título',
type: 'string',
description: 'Si se deja vacío, se usa el título de la página.',
validation: (Rule) => Rule.max(60).warning('Más de 60 caracteres se trunca en Google'),
}),
defineField({
name: 'metaDescription',
title: 'Meta descripción',
type: 'text',
rows: 3,
validation: (Rule) =>
Rule.max(160).warning('Más de 160 caracteres se trunca en Google'),
}),
defineField({
name: 'ogImage',
title: 'Imagen Open Graph',
type: 'image',
description: '1200x630px recomendado. Si se deja vacío, se usa la imagen del sitio.',
}),
defineField({
name: 'noIndex',
title: 'Ocultar de motores de búsqueda',
type: 'boolean',
initialValue: false,
}),
],
})Cómo añadirlo a un documento
Declara un campo con type: "seo" dentro del defineType de cualquier documento. Lo convencional es ponerlo en el grupo "seo":
defineField({
name: 'seo',
title: 'SEO',
type: 'seo', // ← nombre de tipo definido en SEOBase.ts
group: 'seo',
})Asegúrate de que el grupo seo esté declarado en el array groups del documento:
groups: [
{ name: 'content', title: 'Contenido', default: true },
{ name: 'seo', title: 'SEO' },
],Ambos documentos del boilerplate (page e indexPage) ya incluyen este patrón.
Cómo consultarlo desde el front-end
*[_type == "page" && slug.current == $slug][0] {
title,
seo {
metaTitle,
metaDescription,
ogImage,
noIndex
}
}Cómo extenderlo
Si un proyecto necesita campos de SEO adicionales (por ejemplo, canonicalUrl), no modifiques SEOBase.ts directamente si otros proyectos ya lo usan. En su lugar, crea un nuevo objeto que extienda el patrón:
// schemas/objects/SEOExtended.ts
import {defineField, defineType} from 'sanity'
export const seoExtended = defineType({
name: 'seoExtended',
title: 'SEO',
type: 'object',
fields: [
// mismos campos que seoBase...
defineField({
name: 'canonicalUrl',
title: 'URL canónica',
type: 'url',
}),
],
})Registra seoExtended en schemaTypes/index.ts y úsalo con type: "seoExtended" en los documentos que lo necesiten.