Contents
Introducción: qué vamos a conseguir
En este tutorial aprenderás a cachear el HTML generado por WordPress por URL usando transients y claves únicas. La técnica es útil para reducir tiempo de renderizado y consultas a la base de datos en páginas con contenido pesado o con vistas que cambian poco. Verás cómo construir claves estables y únicas por URL, cómo almacenar y recuperar HTML con transients, estrategias para invalidar y limpiar la caché, y precauciones sobre usuarios conectados y caches persistentes (Memcached/Redis).
Conceptos clave antes de empezar
- Transient: API de WordPress para guardar datos temporales (funciones get_transient(), set_transient(), delete_transient()).
- Clave única: identificación única y reproducible por URL para localizar el HTML cacheado.
- TTL (time-to-live): el tiempo en segundos que el transient será válido.
- Normalización de URL: convertir la URL a una forma canónica (ordenar query args, quitar parámetros irrelevantes, etc.).
Principios de diseño
- Cachear sólo para visitantes no autenticados o para roles concretos (evitar cachear contenido personalizado por usuario).
- Generar claves canónicas y reproducibles para evitar duplicados por pequeñas variaciones de URL.
- Usar prefijos en las claves (por ejemplo: html_cache_) para identificar y eliminar fácilmente transients relacionados.
- Diseñar la invalidación: cuando un post cambia hay que eliminar transients asociados.
- Si existe un cache persistente (Redis, Memcached), las operaciones con transients son más rápidas si no, los transients se almacenan en la tabla wp_options.
Helper: generar una clave única por URL (canonical)
Para no cachear versiones duplicadas por parámetros desordenados o por parámetros irrelevantes, normaliza la URL: esquema, host, ruta y parámetros ordenados. El siguiente helper produce una clave final corta usando md5.
v ) { if ( preg_match( /^(utm_fbclidgclid_s=)/, k ) ) { unset( query_args[ k ] ) } } ksort( query_args ) query = build_query( query_args ) } // Normalizar trailing slash: WordPress normalmente usa trailing slash en permalinks path = untrailingslashit( path ) // Construir canonical canonical = scheme . :// . host . path if ( ! empty( query ) ) { canonical .= ? . query } // Añadir contexto opcional: idioma, dispositivo, rol público (si aplica) // Por ejemplo, si usas WPML/Polylang añade la lengua: if ( function_exists( get_locale ) ) { canonical .= . get_locale() } // Generar clave curta con prefijo hash = md5( canonical ) return html_cache_ . hash } ?>
Comentarios sobre la función
- Personalízala según tu sitio: tal vez debas conservar parámetros de query que afectan a la salida (ej.: filtros de tienda).
- Si tu sitio tiene contenido por idioma, incluye el idioma en la clave.
- Si vas a cachear por rol (ej.: visitantes no autenticados vs. invitados), agrega ese contexto en la clave.
Ejemplo: cachear toda la página HTML por URL
Este ejemplo usa buffer de salida para capturar el HTML generado por WordPress y almacenarlo en un transient. La lógica se ejecuta en la acción template_redirect (antes de que el tema imprima el contenido). Se salta el cache para admin, REST API, usuarios logueados y para peticiones AJAX.
Notas prácticas sobre el ejemplo
- Use is_user_logged_in() para evitar cachear contenido que cambia según el usuario. Si necesita cachear por rol, concatene el rol a la clave.
- Evita cachear feeds, endpoints REST o páginas de administración.
- Si su tema imprime cabeceras muy tarde, la llamada a header() puede fallar es sólo para debugging y no imprescindible.
- El uso de exit tras imprimir contenido cached es intencional: evita que WP siga ejecutando hooks innecesarios.
Fragment caching: cachear partes concretas del template
A veces no interesa cachear la página completa, sino secciones concretas. El patrón es similar: generar clave, intentar leer transient, imprimir si existe si no, capturar con ob_start(), generar fragmento, salvar.
Invalidación: cómo borrar transients cuando cambian los datos
La parte más delicada es asegurarse de que cuando el contenido relevante cambia (por ejemplo, guardas o eliminas un post) se eliminen los transients afectados. A continuación dos patrones comunes:
1) Incluir post ID en la clave (fácil de invalidar)
Si el cache está ligado a un post concreto (página o entrada), incluye el post ID en la clave. Entonces, en el hook save_post eliminas clave(s) con ese post ID.
2) Almacenar índice de claves relacionadas para una eliminación masiva
Si tu sistema genera múltiples claves para la misma entidad (por ejemplo, varias variaciones por querystring), guarda la lista de claves asociadas en una opción o en postmeta. Al actualizar el post, recuperas esa lista y borras todos los transients.
Consideraciones sobre el almacenamiento (object-cache/persistent cache)
- Si no tienes un object cache persistente, los transients se guardan en la tabla wp_options almacenar HTML muy grande puede inflar la tabla y causar problemas de rendimiento.
- Si tu hosting soporta Redis/Memcached y tienes un drop-in como object-cache.php, los transients se almacenarán en memoria y serán rápidos y adecuados para HTML pesado.
- Revisa el tamaño máximo de value en tu motor de cache (por ejemplo memcached tiene límite por elemento).
Mejores prácticas y recomendaciones
- Cachea preferentemente sólo para usuarios anónimos. Para usuarios con sesiones, cachea fragmentos que siempre son iguales.
- No utilices TTLs excesivamente largos si tu contenido cambia con frecuencia mejor combinarlos con invalidación por hooks.
- Evita usar URLs sin normalizar: ordena query args y descarta parámetros de tracking.
- Usa prefijos claros en las claves (ej.: html_cache_, html_cache_widget_) y un esquema para relacionarlas con entidades (post_id, taxonomy, etc.).
- Monitorea cabeceras personalizadas (ej.: X-HTML-Cache) para saber si las páginas se sirven desde cache o no.
- En entornos con reverso proxy (Varnish, CDN), combina la cache de aplicación (transients) con la cache HTTP para mejores resultados.
Errores comunes y cómo evitarlos
- Cachear contenido personalizado por usuario: puede devolver datos de usuario A a usuario B. Evítalo incluyendo contexto de usuario en la clave o no cacheando para usuarios logueados.
- No invalidar al actualizar: si no limpias transients cuando cambian posts, la web seguirá mostrando HTML obsoleto.
- Claves inconsistentes: generar clave con una parte no determinista (timestamp, nonce) hará que no haya hit. Usa sólo información reproducible.
- Almacenar HTML extremadamente grande sin object cache: incrementará la tabla wp_options y puede degradar la base de datos.
Comprobación y debugging
- Agrega cabeceras X-HTML-Cache: HIT/MISS como en los ejemplos para monitorizar el comportamiento.
- Usa WP-CLI o consultas SQL para revisar transients en wp_options (prefijo _transient_). Ej.: SELECT option_name FROM wp_options WHERE option_name LIKE %html_cache%.
- En entornos con caché persistente, revisa el dashboard de Redis/Memcached para ver keys y uso de memoria.
Resumen final
Cachear HTML por URL con transients y claves únicas es una técnica poderosa para mejorar el rendimiento de sitios WordPress. Requiere:
- Generar claves canónicas y reproducibles por URL.
- Usar output buffering para capturar HTML completo o fragmentos para transients.
- Invalidar correctamente la caché cuando el contenido cambia (ganchos como save_post, trashed_post, edit_post).
- Considerar el uso de caches persistentes (Redis/Memcached) para almacenar HTML grande sin inflar la base de datos.
Implementando estas prácticas obtendrás mejoras visibles en el tiempo de carga y en la reducción de consultas repetidas a la base de datos.
Recursos
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |