Contents
Introducción
Este artículo explica, paso a paso y con todo detalle técnico, cómo instrumentar errores de JavaScript en un sitio WordPress y reportarlos a un endpoint en el propio WordPress. Verás la implementación front-end (captura y envío de errores), el backend en WordPress (ruta REST, validación, almacenamiento), consideraciones de seguridad, rendimiento, privacidad y cómo visualizar los registros desde el panel de administración.
Visión general
La idea general es:
- Capturar errores JS y promesas no gestionadas en el cliente.
- Enriquecer el evento con contexto (URL, navegador, user agent, usuario WP si aplica, tags personalizados).
- Enviar los eventos al servidor mediante la REST API de WordPress o un endpoint admin-ajax/privado.
- Validar y almacenar los eventos en la base de datos (tabla propia) o externalizar a un servicio de terceros.
- Proveer un panel de administración para consultar y filtrar los eventos.
Recomendaciones iniciales
- Uso de source maps: Sin source maps las trazas están ofuscadas/minificadas. Para una trazabilidad correcta, habilita source maps en producción (con protección) o sube las versiones map a un bucket privado o servicio de resolución de mapas.
- Muestreo (sampling): No envíes el 100% de errores en sites de alto tráfico aplica sampling, por ejemplo 1% o 5% por tipo de error, con reglas para errores críticos.
- Protección de datos y GDPR: No envíes datos personales (PII). Si es necesario, anonimiza (usuario_id en lugar de email) y documenta en la política de privacidad.
- Rendimiento: Haz el envío en background, utiliza batching y backoff exponencial para reintentos.
Captura de errores en el cliente (JavaScript)
Debes capturar:
- Errores sin capturar: window.addEventListener(error)
- Promesas rechazadas no gestionadas: window.addEventListener(unhandledrejection)
- Error global legacy: window.onerror (opcional, pero útil para navegadores antiguos)
Ejemplo de implementación client-side
Este script captura errores, construye una carga útil (payload) y la envía a la REST API de WordPress. Se incluyen batching, reintentos simples y protección de sampling.
// Código: instrumentación de errores en cliente
(function(){
// Configuración inyectada por WP (localize_script)
var ENDPOINT = window.__WP_ERROR_ENDPOINT /wp-json/my-errors/v1/collect
var NONCE = window.__WP_ERROR_NONCE null
var SAMPLE_RATE = (window.__WP_ERROR_SAMPLE_RATE 1) // 1 == 100%
var BATCH_SIZE = 10
var BATCH_INTERVAL = 5000 // ms
var queue = []
var sending = false
function shouldSend() {
return Math.random() < SAMPLE_RATE
}
function buildPayload(errData) {
return {
site_url: location.origin,
page: location.href,
referrer: document.referrer null,
ua: navigator.userAgent,
timestamp: new Date().toISOString(),
error: errData
}
}
function enqueue(event) {
queue.push(event)
if (queue.length >= BATCH_SIZE) {
flush()
}
}
function flush() {
if (sending queue.length === 0) return
sending = true
var batch = queue.splice(0, BATCH_SIZE)
var body = JSON.stringify({events: batch})
var headers = {Content-Type:application/json}
if (NONCE) headers[X-WP-Nonce] = NONCE
fetch(ENDPOINT, {method: POST, body: body, headers: headers, credentials: same-origin})
.then(function(res){
sending = false
if (!res.ok) {
// Re-enqueue with simple retry/backoff (push front)
queue = batch.concat(queue)
// Optional: schedule retry
setTimeout(flush, 5000)
}
}).catch(function(){
sending = false
// Put events back and retry later
queue = batch.concat(queue)
setTimeout(flush, 5000)
})
}
// Handler para window.onerror
window.onerror = function(message, source, lineno, colno, error) {
try {
if (!shouldSend()) return
var err = {
type: error,
message: message,
source: source,
lineno: lineno,
colno: colno,
stack: error error.stack ? String(error.stack) : null,
}
enqueue(buildPayload(err))
} catch(e) {}
// No bloquear ejecución
}
// Handler para promesas no gestionadas
window.addEventListener(unhandledrejection, function(e) {
try {
if (!shouldSend()) return
var reason = e e.reason
var err = {
type: unhandledrejection,
message: (reason reason.message) String(reason) unknown,
stack: (reason reason.stack) ? String(reason.stack) : null
}
enqueue(buildPayload(err))
} catch (ex) {}
})
// Handler de errores capturados por event listeners (p.ej. recursos)
window.addEventListener(error, function(e) {
try {
if (!shouldSend()) return
// event.target puede ser
, 