Deja que la Data API de Webflow ordene los campos que pueda y encárgate del resto en un Route Handler de Webflow Cloud.
Una lista de eventos o productos rara vez mantiene el orden en que la devuelve el CMS. La Data API ahora ordena campos de texto plano, número, fecha e interruptor por ti con sort[field]=desc, por lo que la mayoría de las listas ordenadas solo requieren una solicitud. Sin embargo, los campos de opción y referencia devuelven IDs, y esos necesitan un comparador en tu propio código.
En esta guía, crearemos un Route Handler de Next.js en Webflow Cloud que le pide a la API que ordene donde pueda y realiza la ordenación en la ruta donde no pueda. El token permanece en el servidor y la página recibe una lista ordenada.
¿Qué necesitas para ordenar elementos de una colección desde la Data API en Webflow?
Un detalle a tener en cuenta: la ordenación alfabética en el Designer compara texto, por lo que "10" se ordena antes que "7". La ruta de este tutorial es para listas que tu aplicación renderiza fuera del Designer.
Para la ruta necesitas:
- Una colección con elementos publicados: El CMS limitado del plan Starter es suficiente para seguir los pasos, y el plan Premium cubre el CMS completo y la instalación de la aplicación en un dominio personalizado.
- Un token de sitio: Con el
cms:readámbito. En el sitio de un cliente, es posible que el propietario deba crearlo por ti. - Node.js 22 y npm: Webflow Cloud solo admite el gestor de paquetes npm, por lo que los comandos de instalación usan
npm. - Next.js 15: Fija
create-next-app@15para que el andamiaje se mantenga en Next.js 15, la línea de versiones que admite Webflow Cloud. - Los slugs de los campos para ordenar:
event-date,priceocategory, desde la configuración de cada campo en el CMS.
Si la lista vive en una página de Webflow, es posible que no necesites código en absoluto. Una lista de colección se ordena en el Designer bajo sus ajustes de ordenación, con reglas apiladas por campo, y la guía de ordenación dinámica muestra cómo permitir que el visitante controle la ordenación en una página.
5 pasos para ordenar elementos de una colección desde la Data API en Webflow Cloud
La construcción consiste en un asistente de fetch que solicita páginas ordenadas a la API, un comparador para campos de opción, un Route Handler con una lista de permitidos para las ordenaciones y un componente de cliente que lo invoca.
1. Almacena el token de la API y crea la aplicación
Prepara la estructura de la aplicación y mantén el token fuera del repositorio. Ejecuta esto desde la carpeta donde guardas tus proyectos:
npx create-next-app@15 sorted-items --ts --app --eslint --no-tailwind --no-src-dir --import-alias "@/*" --use-npm --no-turbopack
cd sorted-items
Añade WEBFLOW_API_TOKEN y WEBFLOW_COLLECTION_ID a .env.local, y los mismos dos a tu entorno de Webflow Cloud, marcando el token como secreto. La página de variables de entorno de Webflow indica que ambos tipos están disponibles para la compilación y para la aplicación desplegada en tiempo de ejecución, y que los valores secretos se ocultan en los registros de compilación.
Deja export const runtime = 'edge' fuera de todos los archivos, aunque la página de "bring-your-own-app" todavía lo sugiera para rutas de API. Webflow Cloud se ejecuta en Cloudflare Workers, pero el destino del runtime edge de Next.js es una configuración independiente que el adaptador OpenNext de Cloudflare no admite, por lo que la directiva interrumpe la compilación.
2. Pide a la API de datos que ordene los campos que admite
El endpoint List Live Items acepta sort[<fieldSlug>]=asc o desc para campos de texto plano, correo electrónico, teléfono, número, fecha e interruptor, hasta tres campos por solicitud, aplicados en el orden en que los enumeres.
Para los campos integrados, sortBy acepta , createdOn , lastPublished , lastUpdated y name slug. Un campo de otro tipo, o un slug que no existe, devuelve un error 400.
El asistente llama al mismo endpoint en el host de la API de entrega de contenido, api-cdn.webflow.com, que sirve respuestas en caché que no cuentan para el límite de tasa de la API de datos.
Asistente de la API de Webflow
Crea :lib/webflow.ts
// lib/webflow.ts
const CDN = 'https://api-cdn.webflow.com/v2';
const API = 'https://api.webflow.com/v2';
export type WebflowItem = { id: string; fieldData: Record<string, unknown> };
async function get<T>(url: string): Promise<T> {
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.WEBFLOW_API_TOKEN}`, accept: 'application/json' },
});
if (!res.ok) throw new Error(`Webflow API ${res.status}: ${await res.text()}`);
return (await res.json()) as T;
}
type Page = { items: WebflowItem[]; pagination: { total: number } };
// One page of live items, sorted by the API when `params` carries sort[...] keys.
export async function listLive(collectionId: string, params: URLSearchParams): Promise<WebflowItem[]> {
const page = await get<Page>(`${CDN}/collections/${collectionId}/items/live?${params}`);
return page.items;
}
// Every live item, for sorts the API cannot do.
export async function listAllLive(collectionId: string): Promise<WebflowItem[]> {
const all: WebflowItem[] = [];
let offset = 0;
for (;;) {
const params = new URLSearchParams({ limit: '100', offset: String(offset) });
const page = await get<Page>(`${CDN}/collections/${collectionId}/items/live?${params}`);
all.push(...page.items);
offset += page.items.length;
if (page.items.length === 0 || offset >= page.pagination.total) return all;
}
}
type Field = { slug: string; validations?: { options?: { id: string; name: string }[] } };
// Maps each option ID of an Option field to its display name.
export async function optionNames(collectionId: string, slug: string): Promise<Map<string, string>> {
const collection = await get<{ fields: Field[] }>(`${API}/collections/${collectionId}`);
const field = collection.fields.find((f) => f.slug === slug);
return new Map((field?.validations?.options ?? []).map((o) => [o.id, o.name]));
}
Para una ordenación mediante API, una solicitud devuelve los primeros 100 elementos ya ordenados, lo que cubre una lista de "los 20 más recientes" o una página de catálogo completa sin tener que recopilar cada elemento primero.
3. Escribe un comparador para los campos que la API no puede ordenar
Un campo de opción almacena un ID de opción y un campo de referencia almacena el ID del elemento referenciado, por lo que ordenar los valores sin procesar ordenaría la lista por ID. La solución es cambiar cada ID por su nombre para mostrar antes de comparar. Los nombres de las opciones provienen del esquema de la colección que optionNames lee; un campo de referencia funciona de la misma manera, utilizando los nombres de los elementos de la colección referenciada.
La comparación de texto utiliza Intl.Collator con coincidencia numérica, por lo que "Nivel 2" se ordena antes que "Nivel 10". Los elementos sin valor van al final en cualquier dirección, por lo que una categoría vacía nunca salta a la parte superior de la lista.
Implementación del comparador
Crea :lib/sort.ts
// lib/sort.ts
import type { WebflowItem } from './webflow';
export type SortOrder = 'asc' | 'desc';
const collator = new Intl.Collator('en', { sensitivity: 'base', numeric: true });
export function sortByName(
items: WebflowItem[],
field: string,
names: Map<string, string>,
order: SortOrder,
): WebflowItem[] {
const direction = order === 'desc' ? -1 : 1;
const label = (item: WebflowItem) => {
const id = item.fieldData[field];
return typeof id === 'string' ? (names.get(id) ?? null) : null;
};
return [...items].sort((a, b) => {
const av = label(a);
const bv = label(b);
if (av === null && bv === null) return 0;
if (av === null) return 1;
if (bv === null) return -1;
return collator.compare(av, bv) * direction;
});
}
La función copia la matriz antes de ordenar, y es estable, por lo que los elementos con la misma opción mantienen el orden en que los devolvió la API. Para un sitio localizado, pasa el idioma de la configuración regional a Array.prototype.sortIntl.Collator junto con el cmsLocaleId coincidente en la solicitud.
4. Expón la lista ordenada desde un manejador de rutas
La ruta acepta una clave de ordenación de la cadena de consulta y la busca en una lista de permitidos, por lo que un visitante solo puede solicitar las ordenaciones que hayas definido. Las ordenaciones de la API envían sort[...] a Webflow; la ordenación de opciones recopila cada elemento y utiliza el comparador.
Crea :app/api/items/route.ts
// app/api/items/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { listAllLive, listLive, optionNames } from '@/lib/webflow';
import { sortByName, type SortOrder } from '@/lib/sort';
const SORTS: Record<string, { field: string; order: SortOrder; local?: 'option' }> = {
newest: { field: 'event-date', order: 'desc' },
price: { field: 'price', order: 'asc' },
title: { field: 'name', order: 'asc' },
category: { field: 'category', order: 'asc', local: 'option' },
};
export async function GET(request: NextRequest) {
const collectionId = process.env.WEBFLOW_COLLECTION_ID;
if (!collectionId || !process.env.WEBFLOW_API_TOKEN) {
return NextResponse.json({ error: 'Route is not configured' }, { status: 500 });
}
const key = request.nextUrl.searchParams.get('sort') ?? 'newest';
const sort = SORTS[key];
if (!sort) {
return NextResponse.json({ error: `Unknown sort: ${key}` }, { status: 400 });
}
try {
let items;
if (sort.local === 'option') {
const [all, names] = await Promise.all([
listAllLive(collectionId),
optionNames(collectionId, sort.field),
]);
items = sortByName(all, sort.field, names, sort.order);
} else {
const params = new URLSearchParams({ limit: '100' });
params.set(`sort[${sort.field}]`, sort.order);
items = await listLive(collectionId, params);
}
return NextResponse.json({
count: items.length,
items: items.map(({ id, fieldData }) => ({ id, fieldData })),
});
} catch (error) {
console.error(error);
return NextResponse.json({ error: 'Upstream request failed' }, { status: 502 });
}
}
Cambia los slugs en SORTS para que coincidan con tu colección. La lista de permitidos también evita que slugs arbitrarios entren en la solicitud ascendente, por lo que un visitante no puede provocar un error 400 adivinando nombres de campos. La ruta es pública, lo que es adecuado para contenido publicado; añade autenticación si la lista no es pública.
Ejecuta y solicita : el JSON debería listar los elementos del más barato al más caro, y npm run dev/api/items?sort=price?sort=category debería agruparlos por nombre de opción en lugar de por ID.
5. Llama a la ruta desde el cliente con la ruta base
Un componente de cliente permite al visitante cambiar las ordenaciones. Antepón a su obtención la ruta de montaje, porque Webflow Cloud no reescribe las llamadas del lado del cliente; añade una variable fetchNEXT_PUBLIC_BASE_PATH configurada en la ruta de montaje, ya que Webflow Cloud no la crea.
Crea :app/components/SortedList.tsx
// app/components/SortedList.tsx
'use client';
import { useEffect, useState } from 'react';
type Item = { id: string; fieldData: { name?: string } };
const basePath = process.env.NEXT_PUBLIC_BASE_PATH ?? '';
export default function SortedList() {
const [sort, setSort] = useState('newest');
const [items, setItems] = useState<Item[]>([]);
const [error, setError] = useState(false);
useEffect(() => {
let ignore = false;
fetch(`${basePath}/api/items?sort=${encodeURIComponent(sort)}`)
.then((res) => {
if (!res.ok) throw new Error(String(res.status));
return res.json();
})
.then((data: { items: Item[] }) => {
if (!ignore) {
setItems(data.items);
setError(false);
}
})
.catch(() => {
if (!ignore) setError(true);
});
return () => {
ignore = true;
};
}, [sort]);
return (
<section>
<select value={sort} onChange={(e) => setSort(e.target.value)}>
<option value="newest">Newest first</option>
<option value="price">Price, low to high</option>
<option value="title">Title</option>
<option value="category">Category</option>
</select>
{error && <p>Could not load the list.</p>}
<ul>
{items.map((item) => (
<li key={item.id}>{item.fieldData.name ?? item.id}</li>
))}
</ul>
</section>
);
}
Un selector se activa una vez por cambio, por lo que el componente no necesita debounce. La bandera ignore evita que una respuesta lenta de una ordenación anterior sobrescriba la lista después de que el visitante ya haya elegido otra.
Renderiza el componente desde app/page.tsx, despliégalo y cambia las ordenaciones en la página montada; el panel de red debería mostrar cada solicitud yendo a la ruta de montaje.
¿Qué causa que la ordenación de la API de datos falle en Webflow Cloud?
La mayoría de los fallos se deben a que se solicita a la API que ordene por un campo no compatible, o a las reglas de compilación y enrutamiento de Webflow Cloud.
La ruta devuelve un 502 y el registro muestra un 400 BadArgument.
Causa: La clave hace referencia a un campo que la API no puede ordenar, como un campo de opción, de referencia o un slug que no existe en la colección. La API rechaza toda la solicitud en lugar de ignorar la clave.sort[...]
Solución: Comprueba el tipo de campo en la configuración de la colección. Los campos de texto plano, correo electrónico, teléfono, número, fecha e interruptor se ordenan a través de la API; mueve cualquier otro elemento a una entrada en y corrige el slug si difiere de la configuración del campo.localSORTS
La compilación falla o la lista devuelve un 404 solo después de la implementación.
Causa: Un fallo en la compilación suele significar que un archivo contiene , algo que el adaptador de OpenNext Cloudflare no admite. Un 404 en la página implementada significa que la solicitud del cliente se dirigió a en la raíz del sitio en lugar de bajo la ruta de montaje.export const runtime = 'edge'/api/items
Solución: Elimina la directiva de tiempo de ejecución de todos los archivos y vuelve a implementar. Para el 404, establece en la ruta de montaje exacta y vuelve a implementar, ya que Next.js integra valores públicos durante la compilación.NEXT_PUBLIC_BASE_PATH
La ruta se ralentiza o alcanza el límite 429 una vez que llega tráfico real.
Causa: La ordenación por opciones recopila cada elemento en cada solicitud. En una colección grande, esto supone muchas solicitudes por vista de página y, si el asistente apunta a en lugar del host de entrega, cada una cuenta para el límite de tasa de la API de datos.api.webflow.com
Solución: Mantén el asistente en , donde las respuestas cacheadas no consumen el límite, y prefiere las ordenaciones de la API siempre que el tipo de campo lo permita. Un encabezado en la ruta no servirá de nada, porque Webflow Cloud lo reemplaza por ; la guía de errores 429 cubre el uso de una caché del lado del servidor en su lugar.api-cdn.webflow.comCache-Controlprivate, no-cache
Los elementos aparecen en un orden que parece casi correcto.
Causa: Un número o fecha almacenado en un campo de texto plano se ordena como texto, por lo que "9.5" aparece antes que "10" y las fechas en formatos mixtos se desordenan. Las ediciones recientes también pueden no aparecer porque el host de entrega almacena las respuestas en caché hasta por cinco minutos.
Solución: Almacena los números en un campo de tipo Número y las fechas en un campo de tipo Fecha para que la API los ordene por valor. Para las ediciones recién publicadas, espera a que pase el periodo de caché antes de considerar que el orden es incorrecto.
Qué puedes construir a continuación con la API de datos y Webflow.
El mismo punto de conexión también filtra con , por lo que el siguiente paso es un archivo filtrado, como solo los próximos eventos, ordenados por fecha, en una sola solicitud.filter[<fieldSlug>][<operator>]
Para catálogos que combinan dos colecciones, obtén ambas, intercambia los ID de referencia por nombres y combínalos con el comparador.
Para cada parámetro de lista y los tipos de campo que acepta, la documentación para desarrolladores de Webflow detalla los formatos de valor de los elementos.
Preguntas frecuentes
¿Puedo ordenar por dos campos a la vez?
Sí. Añade una segunda clave a la solicitud, como ; la API los aplica en el orden en que aparecen, hasta un máximo de tres campos. Si uno de los campos es de tipo opción, ordena localmente y compara el segundo campo cuando el primero devuelva 0.sort[...]sort[event-date]=desc&sort[name]=asc
¿La ordenación en un controlador de ruta cuenta para mis límites de Webflow Cloud?
Cada solicitud de visitante ejecuta la ruta, por lo que cuenta para el límite de solicitudes de tu aplicación. Las llamadas que la ruta hace a Webflow son subsolicitudes que no computan para ese total, pero sí afectan al límite de tasa de la API de datos, a menos que el host de entrega las sirva desde la caché.
¿Puedo guardar el resultado ordenado en un archivo usando el módulo fs de Node?
No. El entorno de ejecución de Workers de Webflow Cloud no tiene acceso al sistema de archivos, tal como indica su página de compatibilidad con Node.js, por lo que las llamadas al sistema de archivos fallarán. Utiliza la caché del host de entrega o un enlace de almacenamiento clave-valor para cualquier cosa que calcules por tu cuenta.





