Cloudflare Workers y WordPress: servir WooCommerce desde el edge
Cloudflare Workers ejecuta JavaScript en el borde de la red global de Cloudflare. WordPress ejecuta PHP en un único servidor de origen. Poner Workers delante de WordPress es la arquitectura que permite a una tienda WooCommerce heredar el rendimiento de la red edge sin reescribir el CMS. Las contrapartidas son reales y conviene nombrarlas explícitamente.
Este artículo se ancla en el pilar servicio de WordPress headless y se empareja con la decisión de renderizado ISR vs SSR y la economía del WordPress headless.
TL;DR
- Workers gestiona la ruta de lectura, WordPress gestiona escrituras y autoría.
- El catálogo y el detalle de producto de WooCommerce se renderizan en el edge; el carrito y el checkout se quedan en el origen.
- La invalidación de caché es por webhook, no por tiempo.
- Cloudflare Pages limita el archivo _redirects a 2000 reglas, planifica en torno a eso.
- El plan gratuito de Workers limita el bundle comprimido a 1 MB; el plan de pago lo eleva.
Qué es realmente Cloudflare Workers
Workers es un runtime de isolates V8 que corre JavaScript, TypeScript y WebAssembly dentro de la red edge de Cloudflare (la página de red lista los centros de datos). No es Node.js, no es un contenedor Lambda y no es un sitio donde correr PHP. WordPress se queda en el origen; el Worker es un reverse proxy en JS delante.
Algunas características que delimitan lo que se puede y no se puede hacer con Workers delante de WordPress:
- Sin PHP. Un Worker no ejecuta
wp-load.php. Puede consumir/wp-json/wp/v2/postsy/wp-json/wc/v3/products, transformar la respuesta y devolver HTML o JSON. La instalación WordPress gestiona toda mutación autenticada, incluida la validación HMAC del callback de Bizum o la firma SHA-256 de Redsys, que conviene mantener cerca del plugin del gateway. - La CPU es el presupuesto que aprieta primero. El plan gratuito permite alrededor de 10 ms de CPU por petición, el de pago sube cerca de 30 ms y Unbound va más lejos. Una página de producto ISR servida desde KV gasta casi nada; un template SSR que agrega cuatro llamadas a
/wp-json/y aplica IVA intracomunitario por país comunitario leyendocf-ipcountrypuede rozar el techo del plan gratuito. - Dos capas de almacenamiento, dos modelos de consistencia. Workers KV es eventualmente consistente: lectura local rápida, las escrituras tardan hasta cerca de un minuto en propagarse y en ráfaga se limitan. D1 es SQLite en el edge con consistencia fuerte. Para WooCommerce en ES, KV sirve para listados de catálogo cacheados; el contador de stock vivo durante una campaña y la cola de envío a Verifactu, que necesita orden estricto, deben quedarse en el origen o en Durable Objects.
- El tamaño del bundle cuenta. El script comprimido se sube a 1 MB en el plan gratuito y a 10 MB en el de pago. Una app Astro o Next.js completa, con bundles ES y CA y el cliente REST de WooCommerce, requiere el plan de pago.
- Productos vecinos cubren formas similares. Cloudflare Pages Functions corre en el mismo runtime y es el hogar ergonómicamente correcto para una app Astro o Next.js. Vercel Edge Functions y AWS Lambda@Edge resuelven la misma forma con modelos de coste distintos. Workers gana cuando WordPress ya está detrás del DNS de Cloudflare y el equipo quiere una sola plataforma para caché, WAF y renderizado.
El código escrito contra APIs de la Web Platform (Fetch, Request, Response, Streams, Web Crypto) corre sin cambios. El código que depende de la biblioteca estándar de Node, módulos nativos o acceso al filesystem, no.
La arquitectura en dos capas
En un montaje Workers + WordPress, dos sistemas comparten responsabilidad:
Origen WordPress. Autoría (Block Editor, REST API, WP-CLI), operaciones de escritura (crear, actualizar, eliminar entradas; creación de pedidos; registro de usuarios) y fuente de la verdad para contenido y datos de producto.
Edge Cloudflare Workers. Renderizado de la ruta de lectura (generación de HTML), agregación de API (combinar varios endpoints REST de WordPress en una sola respuesta para el front), edge caching (por ruta, por etiqueta) y aspectos transversales (geo-routing, variantes A/B, reescritura de cabeceras).
La frontera es nítida. Todo lo que muta estado vive en el origen WordPress. Todo lo que lee, renderiza o agrega puede vivir en Workers. Carrito y checkout se sientan en la línea fronteriza porque tienen estado pero son intensivos en lectura.
Patrones concretos de WooCommerce que migran a Workers
Patrones de Workers delante de WooCommerce que hemos entregado o visto entregar limpiamente en tiendas españolas:
Caché edge para lecturas /wp-json/. Una ruta Worker hace match con /wp-json/wc/v3/products* y sirve desde caché cuando la clave (URL más un pequeño conjunto de cabeceras vary) está fresca. Endpoints sensibles a stock como /wp-json/wc/v3/products/<id> reciben TTL más corto e invalidación por webhook en la acción woocommerce_product_set_stock. El origen PHP deja de gestionar el fan-out de listados que viene de exportadores de feeds para Idealo y Google Shopping, scrapers de precios y crawlers automatizados.
Caché de página consciente del carrito. La página de catálogo se cachea, pero el fragmento de mini-carrito no. El Worker lee la cookie wp_woocommerce_session_*, va a buscar el fragmento al origen y cose la respuesta. El HTML del catálogo permanece cacheable entre todos los anónimos; el fragmento del carrito es por sesión y nunca se cachea. Mismo patrón sirve para inyectar el botón Bizum con el merchantParameters ya firmado en un esqueleto público que sigue siendo estático.
Transformación de imagen en el edge. Las imágenes de producto se suben a la media library de WordPress en resolución completa. Una ruta Worker delante de /wp-content/uploads/ redimensiona, recodifica a AVIF y cachea en el edge. El origen deja de ejecutar Imagick en cada petición no cacheada, que durante una campaña en El Corte Inglés o Black Friday es una de las fuentes de CPU más ruidosas en una caja WooCommerce.
Redirecciones y variantes geo. El Worker lee cf-ipcountry y separa peninsular de Canarias, Ceuta y Melilla para mostrar la tarifa SEUR o MRW correcta y aplicar IGIC en lugar de IVA al 21 por ciento, o asigna cohorte A/B sin viaje a PHP. Canarias es territorio fiscal aparte y la calculadora del edge tiene que tratarlo como tal: el mismo SKU vale distinto según el destino. La misma lógica en WordPress obliga a pasar por wp-load.php para leer is_canarias_visitor() desde un plugin.
Reglas WAF más allá de WAF Pro. Bloquear POST a /xmlrpc.php, limitar consultas /?s= por ASN único, dropear peticiones que traigan wp-config en el path, o validar la firma HMAC del callback de Bizum y la firma de Redsys antes de que lleguen a PHP. Workers da una capa programable sobre el WAF gestionado sin pagar slots de reglas Enterprise.
Lo que se queda en el origen WordPress: guardados del Block Editor, creación de pedido desde checkout autenticado, callbacks de pasarelas (Redsys, Bizum, transferencia), proxy de envío a Verifactu y AEAT, sesiones de admin y el fan-out de webhooks que dispara invalidación en el Worker. El servidor PHP escala al volumen editorial y al volumen de pedidos, no al volumen de tráfico anónimo de catálogo.
Dónde trazar la frontera
Tres categorías de ruta, tres reglas de renderizado distintas:
Estático o ISR en el edge. Páginas de marketing, entradas de blog, archivos de categoría, páginas de detalle de producto. Cacheadas agresivamente con invalidación por webhook.
SSR en el edge sin caché. Carrito, cuenta, dashboards, páginas de checkout que son personalizadas y dirigidas por sesión. Workers ejecuta el render en cada petición; WordPress provee los datos vía REST.
Solo origen, sin Worker. WP Admin (/wp-admin/), el Block Editor y los endpoints REST del core de WordPress usados internamente para autoría. La configuración de rutas del Worker los excluye explícitamente de la capa edge.
El error común es intentar mover el carrito a la caché edge. El carrito es estado por usuario; cachearlo entre usuarios es un incidente de seguridad esperando ocurrir. SSR en el edge es el modelo correcto: el Worker renderiza el HTML del carrito de ese usuario, pero no cachea el resultado.
Invalidación de caché, la pieza portante
ISR en el edge solo es correcto cuando la invalidación es correcta. El patrón que funciona:
Etiqueta cada respuesta cacheada. Cada página renderizada se etiqueta con los IDs de entrada, IDs de término e IDs de producto de WordPress que referencia. La caché de Cloudflare Workers soporta purgado por etiquetas vía la API de caché.
Webhook en cada escritura de WordPress. Publicación, cambio de slug, eliminación de entrada, actualización de stock, cambio de precio. Cada uno dispara un webhook a una ruta Workers que traduce “la entrada 8421 cambió” en “purga la etiqueta wp-post-8421” vía la API de Cloudflare.
Revalidación por tiempo solo como salvaguarda. Una ventana stale-while-revalidate de 1 hora cubre fallos de entrega de webhooks. No es el mecanismo principal. Un sitio que revalide cada 60 segundos reconstruye 60 veces por hora cada página; en 5000 páginas son 300000 renderizados innecesarios.
El orden importa: invalida y luego escribe. Cuando una publicación de WordPress dispara el webhook, el Worker invalida la etiqueta y la siguiente petición reconstruye la página desde el origen ya actualizado. Si se invierte el orden, un render obsoleto se cuela en la caché y persiste hasta la siguiente invalidación.
Límites a planificar
Límites de plataforma documentados por Cloudflare:
- Tope de
_redirectsen Cloudflare Pages: 2000 reglas. Por encima, los deploys fallan. Lo seguimos en la pipeline de build y estamos actualmente en 1600. - Tamaño del bundle del Worker: 1 MB comprimido en el plan gratuito, mayor en planes de pago. Las rutas que entregan aplicaciones completas Astro o Next.js requieren el plan de pago.
- Tiempo de CPU por petición: 10 ms en el plan gratuito, 50 ms o más en los de pago. SSR con lógica de plantilla pesada cruza rápido el techo del plan gratuito; las respuestas cacheadas vía ISR consumen prácticamente nada de CPU.
- Subpeticiones por petición: 50 en el plan gratuito, más en los de pago. La agregación REST de WordPress que se ramifica a varios endpoints choca con esto en páginas complejas.
La respuesta arquitectónica habitual: diseña para el plan de pago, despliega en el plan de pago, trata el plan gratuito como sandbox de desarrollo.
Compatibilidad con Astro y Next.js
Según el veredictos de stack Q3 2026, tanto Astro 5+ como Next.js 15 entregan adaptadores oficiales de Cloudflare. El adaptador de Astro compila las rutas estáticas + SSR a Workers; el de Next.js hace lo mismo con el App Router. Ambos producen un artefacto de deploy que corre en Cloudflare Pages con Workers por debajo.
La elección entre ellos está cubierta en la matriz de decisión Next.js vs Astro. Para una tienda WooCommerce orientada a contenido, Astro suele ser la opción por defecto porque el modelo static-first se mapea limpiamente al catálogo. Para un montaje más orientado a aplicación (cuenta, dashboard, personalización compleja), el modelo de server components de Next.js tiene la ventaja ergonómica.
En cualquier caso, el origen WordPress queda inalterado. Workers + WordPress es un patrón arquitectónico, no una elección de framework.
Formas de fallo que conviene conocer antes de entregar
Algunas maneras concretas en que hemos visto un montaje Workers + WordPress romperse o sorprender al equipo en tiendas ES:
Limitación de escrituras KV en invalidación a ráfagas. Una importación en bulk del ERP que toca 5000 SKUs dispara 5000 webhooks woocommerce_update_product. El Worker traduce cada uno en una escritura KV por clave de SKU. El throughput de escritura del KV está limitado por namespace, las escrituras se encolan y la caché queda obsoleta durante minutos, con precios y stock que no coinciden con los enviados a Verifactu. El arreglo: hacer debounce en el lado WordPress y agrupar las invalidaciones, o cambiar el mapa por SKU por una sola llamada de purga por etiqueta contra la API de caché de Cloudflare.
Cold-start vs warm-start en locales de tráfico bajo. Un isolate V8 reutilizado entre peticiones casi no añade coste de arranque. La primera petición a una región tras una ventana larga de inactividad paga 5 a 50 ms extra mientras el isolate arranca y el script se parsea. Para la ruta CA o EU de una tienda que sirva sobre todo desde Madrid y Barcelona, el p99 se ve peor que el p50. Monitores sintéticos desde varias localidades reparten el problema; el RUM lo desnuda.
Tope de 1 MB en el plan gratuito. Una app Next.js 15 completa, con adaptador Cloudflare, react-server-dom, bundles ES y CA, calculadora de IVA intracomunitario y tipo IGIC para Canarias y el cliente REST de WooCommerce, supera fácil 1 MB comprimido. El deploy falla en el upload, no en runtime. Se planifica para el de pago (10 MB) o se divide el render entre varios scripts Worker.
Fan-out de subpeticiones en páginas agregadas. Una página de categoría que va a buscar el término, los productos, las categorías relacionadas, las breadcrumbs, el menú y la tabla de tarifas SEUR o MRW por código postal toca seis endpoints /wp-json/. El plan gratuito tope subpeticiones a 50 por invocación Worker, el de pago a 1000. Capas de agregación que pre-componen la respuesta en el lado WordPress, o un endpoint GraphQL único vía WPGraphQL, mantienen el conteo predecible.
Fallos de entrega de webhooks dejando caché obsoleta. WordPress dispara el webhook en la acción shutdown; si el worker PHP-FPM expira o si la red cae entre la confirmación del callback Redsys y el do_action, el webhook nunca llega al Worker. Un stale-while-revalidate de 1 hora basado en etiquetas atrapa esto; sin la salvaguarda, el render obsoleto persiste hasta la siguiente purga manual.
Las fases de migración (auditoría, scaffolding REST y webhooks, build y cutover, observabilidad) están documentadas en el schema howTo al inicio de este artículo. Las ejecutamos dentro de nuestro servicio de WordPress headless. El precio es individual porque TTFB y TTI dependen de la carga de plugins del origen, del framework elegido y del perfil real de tráfico; el scaffold de benchmark documenta el protocolo de medición al que nos vinculamos.
Dónde encaja esto
Este artículo pilar se ancla en el clúster servicio de WordPress headless. Para la elección de framework ver la matriz de decisión Next.js vs Astro. Para la elección de renderizado por ruta ver la decisión ISR vs SSR. Para riesgos de migración SEO ver la checklist de patrones SEO de WordPress headless. Para el encuadre de costes ver la economía del WordPress headless 2026.

