Complemento del blog · Archivo de categoría

El Archivo de categoría: agrupar el blog por tema

La página que reúne todos los artículos de una categoría. No se escribe a mano ni una por una: una ruta dinámica calcula las categorías con contenido y genera el archivo de cada una, con su listado y su URL propia.

Esta página no es una ficha técnica: es el complemento entero, abierto y explicado. Qué problema resuelve y por qué gana su lugar en el blog, de qué piezas se compone, cómo se comporta en el teléfono, dónde encaja y, al final, cómo está construido —del criterio de diseño a la línea de código—.

Con un matiz propio que conviene marcar: no se genera una página por cada valor del enum, sino una por cada categoría USADA por los artículos. Un Set sobre la colección decide cuáles existen, así que nunca queda un archivo vacío y publicar un .mdx actualiza el archivo de su tema solo.

Definición

¿Qué es el archivo de categoría?

La página que agrupa los artículos de una categoría del blog —/blog/categoria/<cat>—: una vista temática, con su propio título y su listado, generada por cada categoría con contenido.

El archivo de categoría es la página que responde a «muéstrame todo lo de este tema». En el blog, cada artículo lleva UNA categoría —un enum cerrado: guías, novedades, general—; el archivo reúne en una sola página todos los que comparten esa categoría, en /blog/categoria/<cat>. Es el índice temático que un artículo suelto, por sí solo, no ofrece.

No se inventó aquí: es el patrón de archivo de cualquier blog o medio —«ver todo lo de Recetas», «ver todo lo de Opinión»—. En esta plantilla, además, no es estático: es una ruta dinámica que mira la colección de artículos, calcula qué categorías tienen contenido y emite una página por cada una. El archivo refleja siempre el blog real.

Función e importancia

¿Para qué sirve?

Hace tres trabajos: crea una vista de archivo temática e indexable (SEO de cola más amplia), reparte autoridad por tema con enlazado interno, y se genera sola —una por categoría usada—.

Su función es darle al tema una página propia. Un artículo responde a una búsqueda concreta; el archivo de categoría responde a una más amplia —«todo lo de este tema»— y, de paso, le ofrece al lector que llegó a un artículo la forma de seguir leyendo sobre lo mismo. Convierte una colección dispersa de entradas en un cuerpo temático navegable.

Y por eso pesa más de lo que parece. Para el SEO, es una URL de archivo indexable que puede posicionar por términos de cola más amplia y que concentra señales de un tema. Para el lector, es la puerta a «más de esto». Para el mantenimiento, es gratis: se genera sola, una por categoría con contenido, sin páginas que cuidar a mano.

Vista de archivo temática e indexable

Cada categoría obtiene su propia URL —/blog/categoria/<cat>— con su título, su descripción y su listado. Para el lector es «todo lo de este tema» de un vistazo; para el buscador, una página de archivo que puede posicionar para búsquedas más amplias que las de un artículo suelto. Es SEO de cola larga sin escribir contenido nuevo.

Enlazado interno que reparte autoridad por tema

El badge de cada artículo y el widget «Categorías» del sidebar apuntan aquí con anchor text real —el nombre de la categoría—. Eso concentra señales temáticas en una página y reparte equity interno entre los artículos relacionados. El archivo se vuelve el nodo que agrupa y conecta todo un tema del blog.

Se genera sola, una por categoría usada

No hay páginas que mantener a mano: la ruta dinámica calcula las categorías con contenido y crea una página por cada una en el build. Publicar un .mdx en una categoría lo suma a su archivo; estrenar una categoría crea su página sola. Cero listas paralelas, cero archivos vacíos, cero desincronización.

Anatomía

¿Qué lleva el archivo de categoría?

Cinco piezas: la ruta dinámica, el cálculo de categorías usadas (Set), el filtro de artículos de la categoría, el enlace de entrada (badge + sidebar) y el listado con su SEO de archivo.

Cada pieza cumple un papel claro. La ruta dinámica vale por todas las categorías; el Set decide cuáles existen; el filtro arma el subconjunto de cada una; el enlace de entrada lleva al lector hasta aquí; y el listado, con su título y su conteo, es la cara visible del archivo. Visibles arriba (listado y conteo), invisibles abajo (ruta, Set y filtro), pero todas necesarias.

Abajo, el ejemplo en vivo —réplica anotada a escala de la página de archivo—. Cada punto numerado se desglosa en su tarjeta: qué resuelve y de qué dato sale. A diferencia de una página escrita a mano, aquí el listado viene del filtro sobre la colección, así que publicar en la categoría lo actualiza solo.

1

La ruta dinámica

Un solo archivo [...categoria].astro que vale por todas las categorías. Su getStaticPaths declara los params y, por cada categoría, Astro emite una página estática en build: /blog/categoria/<cat>. No se escribe una página por tema a mano.

Dato [...categoria].astro · getStaticPaths()

2

El cálculo de categorías usadas

Se recorren los artículos no-draft y se reduce a las categorías DISTINTAS que aparecen, con un Set. Así solo se generan las páginas de categorías que realmente tienen contenido —no las del enum entero— y nunca queda un archivo vacío.

Dato [...new Set(posts.map(p => p.data.category))]

3

El filtro de artículos

Cada página recibe como prop los artículos cuya categoría coincide. Es el subconjunto del blog que esa página lista: el filtro corre una vez en build, no en cada visita. La categoría es un enum cerrado y única por artículo, así que el filtro es exacto.

Dato posts.filter(p => p.data.category === categoria)

4

El enlace de entrada

Nadie teclea estas URLs: se llega desde el badge de categoría de cada artículo (en ArticleLayout) y desde el widget «Categorías» del sidebar. Ese anchor text real reparte autoridad hacia el archivo y le da contexto temático al buscador.

Dato badge + sidebar → /blog/categoria/<cat>

5

El listado y el SEO de archivo

La página pinta su Hero, un SectionHeading con el conteo y la rejilla de CategoryCard. El title, la description y el H1 incluyen el nombre de la categoría: una vista de archivo temática, indexable, con su propia URL.

Dato title/description/H1 + conteo · CategoryCard

Variantes

Otros diseños y aplicaciones

El de esta plantilla es un archivo simple —título, conteo y rejilla—, pero la página cambia de cara según el blog: con descripción del tema, con contador destacado, paginada, con portada de categoría o con orden y subfiltros.

No hay un único modelo: hay una misma idea —una página por tema que agrupa sus artículos— que cada proyecto ajusta. Una revista suma un párrafo introductorio; un archivo extenso lo pagina; un magazine le pone portada a cada categoría; una base de conocimiento añade orden y subfiltros.

Abajo, seis variantes —la primera es la configuración real de la ruta, y el resto son extensiones que requieren sumar datos por categoría o algo de lógica—. Cada una con su réplica en vivo y el tipo de proyecto donde rinde mejor.

  • Archivo simple (esta plantilla)

    Negocio · Blog

    El de esta plantilla: Hero, título con el conteo y la rejilla de tarjetas, sin más. Es el patrón más seguro y el que mejor reutiliza la card y la rejilla del listado. Configuración real de la ruta /blog/categoria/<cat>.

  • Con descripción de categoría

    Editorial · Revista

    El mismo archivo con un párrafo introductorio que explica de qué va el tema, encima de las tarjetas. Útil para dar contexto y sumar texto indexable. Se logra añadiendo una descripción por categoría a la fuente de datos.

  • Con conteo / contador

    Blog grande · Catálogo

    Muestra de forma destacada cuántos artículos hay en la categoría —«24 artículos»—, no solo en el subtítulo. Ya sale del mismo dato (posts.length); aquí solo gana protagonismo visual como señal de volumen del archivo.

  • Paginado (cuando crece)

    Archivo extenso

    Cuando una categoría acumula muchas entradas, el listado se parte en páginas —el mismo patrón que la paginación del blog—. Extensión: el getStaticPaths añade el número de página al params y reparte los posts por tramos.

  • Con imagen / encabezado de categoría

    Magazine · Portada

    Un encabezado de archivo más rico: imagen o color propio de la categoría sobre el título, a modo de portada temática. Variante visual del mismo Hero; requiere asociar una imagen a cada categoría en la fuente de datos.

  • Con orden o subfiltros

    Knowledge base

    Dentro del archivo, controles para ordenar (recientes / antiguos) o acotar por subtema. Útil en categorías muy pobladas. Extensión: el orden puede resolverse en build; los subfiltros piden algo de lógica adicional.

Responsive y móvil

Cómo se comporta en el teléfono

En móvil el archivo no se aprieta: la rejilla baja a una columna, el encabezado (título + conteo) se acomoda legible y cada tarjeta es un objetivo táctil cómodo.

En escritorio el archivo muestra su rejilla a tres columnas bajo un encabezado con el tema y su conteo. En el teléfono no hay ancho para tres tarjetas, así que la rejilla pasa a una sola columna (dos en tablet) —la MISMA rejilla del listado del blog, sin componente nuevo—. El contenido manda y nada desborda.

A partir de ahí, tres patrones según lo que pida la pantalla: que la rejilla del archivo crezca 1 → 2 → 3, que el encabezado (título y conteo) quede legible sin apretarse, y que cada tarjeta sea un objetivo táctil de al menos 44 px. Cada uno, abajo, con su vista en el teléfono y su receta.

1 · Rejilla del archivo 1 → 2 → 3 (default)

Mobile-first: el grid arranca en 1fr y sube a dos columnas en tablet y tres en escritorio. Es exactamente la rejilla del listado del blog reutilizada; el archivo no estrena layout y se ve idéntico al resto.

CSS · rejilla del archivo 1→2→3
/* MÓVIL · la rejilla del archivo crece 1 → 2 → 3 columnas.
   Una sola columna en el teléfono; dos en tablet; tres en
   escritorio. Es la MISMA rejilla del listado del blog. */

.grid { display: grid; grid-template-columns: 1fr; gap: var(--sp-5); }

@media (min-width: 640px)  { .grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .grid { grid-template-columns: repeat(3, 1fr); } }

2 · Encabezado de archivo legible

El título («Categoría: Guías») baja de tamaño en pantallas estrechas y el conteo cae debajo, no al costado, para no apretarse. El H1 sigue siendo uno solo y el tema queda claro de un vistazo, sin desbordar la línea.

CSS · encabezado legible en móvil
/* MÓVIL · el encabezado del archivo, legible en pantalla chica.
   El título («Categoría: Guías») y el conteo no se aprietan: el
   título baja de tamaño y el conteo va debajo, no al costado. */

@media (max-width: 480px) {
  .acg-h1    { font-size: var(--text-2xl); line-height: var(--leading-tight); }
  .acg-count { display: block; margin-top: var(--sp-1); font-size: var(--text-sm); }
}

3 · Área táctil de las cards (≥44 px)

En el teléfono se toca con el dedo: el enlace cubre la tarjeta entera y deja al menos 44 px de alto, el objetivo táctil recomendado. Toda la card es un solo target —imagen, título y CTA—, así no hay toques fallidos.

CSS · objetivo táctil 44px
/* Área táctil de las cards: toda la tarjeta es el objetivo.
   El enlace cubre la card entera y deja ≥ 44 px de alto, para
   tocarse con el dedo sin fallar. */

@media (max-width: 768px) {
  .grid > * a { display: block; min-height: 44px; }   /* card = un solo target */
}

Posición

¿Dónde se coloca?

No es una sección dentro de otra página: es una página propia —/blog/categoria/<cat>—, una por categoría usada. Se llega a ella desde el blog, no se incrusta.

El archivo de categoría es una ruta en sí misma, no un bloque que se mete en otra página. Vive en /blog/categoria/<cat> y se genera una por cada categoría con contenido. Su lugar en el sistema es ser el destino: las puertas que llevan hasta él son el badge de categoría de cada artículo y el widget «Categorías» del sidebar.

Por eso no se repite ni se incrusta: es el nodo que agrupa un tema, y los demás complementos del blog apuntan hacia él. Forma pareja con el archivo de etiqueta (la misma idea, pero por tema transversal), reutiliza la tarjeta del listado y recibe su tráfico interno del sidebar.

Piezas cercanas: el archivo de etiqueta (la misma idea, por tema transversal), la tarjeta de artículo (la card que llena la rejilla, con el badge que enlaza aquí) y el sidebar (cuyo widget «Categorías» trae el tráfico).

Implementación

Cómo está construido

Una ruta dinámica ([...categoria].astro) cuyo getStaticPaths calcula las categorías usadas con un Set y, por cada una, pasa como props la categoría y sus artículos filtrados. El enlace de entrada llega desde el badge del artículo.

El reparto es deliberado. En vez de una página .astro por tema, hay un solo archivo —[...categoria].astro— que vale por todas las categorías. Su getStaticPaths lee la colección de artículos no-draft, calcula con un Set las categorías DISTINTAS que aparecen (no las del enum entero) y emite una página por cada una, con sus posts ya filtrados en las props.

El resto es presentación: cada página pinta su Hero, un SectionHeading con el conteo y la rejilla de CategoryCard —la misma del listado—. El title, la description y el H1 incluyen el nombre de la categoría, así que cada archivo tiene su propio SEO. Y el lector llega aquí porque el badge del artículo (en ArticleLayout) y el widget del sidebar enlazan a /blog/categoria/<cat>. Cero JavaScript: todo se genera en build.

Astro · la ruta dinámica (cats únicas con Set + map a params/props)
---
// /blog/categoria/[...categoria].astro · genera UNA página por categoría USADA.
import { getCollection } from 'astro:content'

export async function getStaticPaths() {
  const posts = (await getCollection('articulos', ({ data }) => !data.draft))
    .sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf())

  // Categorías DISTINTAS que aparecen en los artículos (no el enum entero).
  const cats = [...new Set(posts.map((p) => p.data.category))]

  return cats.map((categoria) => ({
    params: { categoria },
    props: {
      categoria,
      posts: posts.filter((p) => p.data.category === categoria),
    },
  }))
}

const { categoria, posts } = Astro.props
---
TypeScript · el filtro de artículos de la categoría
// EL FILTRO · cada página recibe solo los artículos de su categoría.
// La categoría es un enum cerrado y ÚNICA por artículo, así que la
// comparación estricta basta —no hay que normalizar ni dudar del tipo—.

const delTema = posts.filter((p) => p.data.category === categoria)

// 'delTema' es el subconjunto que lista esta página. Corre una vez en
// build (no por visita) y, como sale del Set de arriba, nunca queda vacío.
Astro · el enlace de entrada desde el artículo (badge → /blog/categoria/<cat>)
---
// EL ENLACE DE ENTRADA · el badge del artículo apunta a su archivo.
// (en ArticleLayout.astro · también lo hace el widget «Categorías» del sidebar)
const { category } = Astro.props
---

{category && (
  <a class="post__cat" href={`/blog/categoria/${category}`}>
    {category}   {/* anchor text real = nombre de la categoría */}
  </a>
)}

En concreto: getStaticPaths hace el trabajo de una vez —ordena los artículos por fecha, deriva las categorías con [...new Set(posts.map(p => p.data.category))] y, por cada una, devuelve { params: { categoria }, props: { categoria, posts } } con el filtro posts.filter(p => p.data.category === categoria). Como la categoría es un enum cerrado y única por artículo, la comparación estricta basta.

La página de destino es presentacional: recibe categoria y posts por props, calcula posts.length para el conteo del <SectionHeading> y recorre los artículos con map hacia <CategoryCard>. El title, la description y el <h1> llevan el nombre de la categoría —SEO de archivo—, y el lector entra por el badge de cada artículo y el widget del sidebar. Todo HTML estático generado en build, sin consultas por visita.

Buenas prácticas

Qué hacer y qué evitar

La diferencia entre un archivo de categoría que ayuda y uno que estorba cabe en un puñado de hábitos —empezando por tener pocas categorías bien definidas—.

Ninguno de estos hábitos es capricho: salen de mirar dónde tropieza un blog cuando las categorías crecen sin criterio. Un archivo sano nace de pocas categorías bien definidas, genera una página por categoría USADA, escribe su title y description con claridad y se enlaza desde el badge. Uno que estorba multiplica categorías casi iguales, crea páginas vacías del enum o duplica el listado a mano.

La buena noticia es que casi todo se sostiene solo cuando las páginas salen del Set sobre la colección y el listado reutiliza la tarjeta del blog. Abajo, lo que conviene y lo que conviene evitar, enfrentados.

Sí conviene

  • Mantén pocas categorías bien definidas: cada una, un interés real con contenido suficiente.
  • Genera una página por categoría USADA (Set sobre los posts), no una por el enum entero.
  • Escribe title y description de archivo claros, con el nombre de la categoría y el tema.
  • Enlaza el badge del artículo y el widget del sidebar a su archivo, con anchor text real.
  • Reutiliza la tarjeta y la rejilla del listado: el archivo se ve idéntico, sin layout nuevo.

Mejor evita

  • No generes una página por cada valor del enum: las categorías sin artículos quedan vacías.
  • No multipliques categorías casi iguales: dispersan el contenido y diluyen la autoridad.
  • No dupliques el listado a mano por categoría: una ruta dinámica lo hace solo.
  • No dejes el badge del artículo sin enlace: es la puerta de entrada al archivo.
  • No confundas categoría (una, enum cerrado) con etiqueta (varias, abiertas): son piezas distintas.
¿Necesitas ayuda?