Cómo crear una página índice
Una página índice (type: "indexPage") es un documento que actúa como listado de sub-documentos — una página raíz donde el front-end renderiza una colección de entradas debajo de ella. Úsala para /blog, /casos o /servicios.
Cuándo usar este tipo
Usa indexPage cuando la página:
- Lista documentos de un tipo específico (
post,caseoservice) - Tiene secciones propias antes y después del listado
- Necesita su propia URL base y SEO (ej:
/blogindependiente de/blog/mi-post)
La diferencia con page es que indexPage delega el contenido principal al listado de la colección. El editor configura qué colección mostrar y añade contexto arriba y abajo de ese listado.
Campos disponibles
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
title | string | Sí | Nombre interno del documento. Solo visible en el Studio. |
slug | slug | Sí | La URL base. Ej: blog → /blog |
collectionType | string | Sí | Qué tipo de documentos lista esta página |
sectionsTop | array | No | Secciones que aparecen antes del listado |
sectionsBottom | array | No | Secciones que aparecen después del listado |
seo | seo | No | Metadatos de SEO |
Valores de collectionType
| Valor | Título en Studio | Uso previsto |
|---|---|---|
"post" | Blog — Posts | Entradas de blog |
"case" | Casos de estudio | Proyectos o casos de clientes |
"service" | Servicios | Fichas de servicios del estudio |
Código fuente
// schemas/documents/indexPage.ts
import { defineField, defineType } from "sanity"
import { sectionsField } from "../helpers/sections"
export const indexPageDocument = defineType({
name: "indexPage",
title: "Páginas Índice",
type: "document",
groups: [
{ name: "content", title: "Contenido", default: true },
{ name: "seo", title: "SEO" },
],
fields: [
defineField({
name: "title",
title: "Título interno",
type: "string",
validation: (Rule) => Rule.required(),
group: "content",
}),
defineField({
name: "slug",
title: "Slug base",
type: "slug",
description: "La ruta base. Ej: 'blog' → /blog, y los posts serán /blog/[slug]",
options: { source: "title" },
validation: (Rule) => Rule.required(),
group: "content",
}),
defineField({
name: "collectionType",
title: "Tipo de colección",
type: "string",
description: "Define qué documentos lista esta página índice",
options: {
list: [
{ title: "Blog — Posts", value: "post" },
{ title: "Casos de estudio", value: "case" },
{ title: "Servicios", value: "service" },
],
layout: "radio",
},
validation: (Rule) => Rule.required(),
group: "content",
}),
defineField({
name: "sectionsTop",
title: "Secciones superiores",
description: "Se muestran antes del listado de items",
type: "array",
of: sectionsField.of,
group: "content",
}),
defineField({
name: "sectionsBottom",
title: "Secciones inferiores",
description: "Se muestran después del listado de items",
type: "array",
of: sectionsField.of,
group: "content",
}),
defineField({
name: "seo",
title: "SEO",
type: "seo",
group: "seo",
}),
],
preview: {
select: {
title: "title",
slug: "slug.current",
collectionType: "collectionType",
},
prepare: ({ title, slug, collectionType }) => ({
title,
subtitle: `/${slug} · ${collectionType}`,
}),
},
})sectionsTop y sectionsBottom no usan el spread completo de sectionsField sino solo sectionsField.of (el array de tipos). Esto les permite tener sus propios name, title y description mientras comparten el mismo conjunto de tipos de sección disponibles.
Crear una página índice en el Studio
- En el Studio, abre el tipo Páginas Índice en la barra lateral
- Haz clic en Nuevo documento
- Ingresa el Título interno (ej:
Índice — Blog) - Genera el Slug base (ej:
blog) - Selecciona el Tipo de colección (
Blog — Posts,Casos de estudiooServicios) - Opcionalmente, añade secciones en Secciones superiores (hero, intro) y Secciones inferiores (CTA, newsletter)
- Publica el documento
Consulta GROQ para el front-end
// Obtener la página índice del blog con sus secciones
*[_type == "indexPage" && slug.current == "blog"][0] {
title,
slug,
collectionType,
sectionsTop[] {
_type,
eyebrow,
heading,
subheading,
ctas[] { label, href, variant },
image { asset->, hotspot, crop },
variant
},
sectionsBottom[] {
_type,
eyebrow,
heading,
subheading,
ctas[] { label, href, variant },
image { asset->, hotspot, crop },
variant
},
seo {
metaTitle,
metaDescription,
ogImage,
noIndex
}
}// Obtener los posts para renderizar el listado
*[_type == "post"] | order(_createdAt desc) {
_id,
title,
slug,
// ...campos del documento post
}El front-end es responsable de combinar los datos del indexPage con el listado de documentos de la colección correspondiente.
Añadir un nuevo collectionType
Si un proyecto necesita una colección no incluida en el boilerplate (ej: "team" para una página de equipo), añade la opción al array list del campo collectionType en indexPage.ts:
options: {
list: [
{ title: "Blog — Posts", value: "post" },
{ title: "Casos de estudio", value: "case" },
{ title: "Servicios", value: "service" },
{ title: "Equipo", value: "team" }, // ← nuevo
],
layout: "radio",
},Luego asegúrate de que el front-end maneje el nuevo valor en su lógica de renderizado.