Cuando una empresa te contrata para tocar su web, el escenario real es otro: la tecnología es el vehículo, la empresa compra la necesidad de entender el destino de ese vehículo. No compra un plugin, ni una función, ni una línea de código bonita. Compra la certeza de que, si algo se rompe, alguien va a saber qué pasó, dónde y por qué — antes de que se convierta en un cliente enfadado o un pedido perdido.
El problema es que la mayoría de fallos en WordPress son silenciosos. No hay un cartel rojo que diga "esto ha fallado". Simplemente... no pasa nada. Y "no pasa nada" es lo más caro que existe cuando debería haber pasado algo.
El ejemplo perfecto: el email que nunca llega
WordPress envía correos con wp_mail(), que por debajo usa la función mail() de PHP. Muchísimos hostings la bloquean o la limitan para evitar spam. Resultado: un pedido de WooCommerce se confirma en la base de datos, pero el email de confirmación nunca sale. El cliente no recibe nada, piensa que algo ha ido mal, y te escribe enfadado — o directamente no vuelve.
Nadie se entera. Ni tú, ni el dueño del negocio. Hasta que ya cuesta dinero.
La solución mínima: engancharse al fallo real
WordPress dispara un hook específico cuando el envío falla: wp_mail_failed. Con esto ya tienes medio sistema de logs hecho:
add_action( 'wp_mail_failed', 'i8_log_mail_error' );
function i8_log_mail_error( $wp_error ) {
$log_line = sprintf(
"[%s] EMAIL FALLIDO | Destinatario: %s | Error: %s\n",
current_time( 'mysql' ),
$wp_error->get_error_data()['to'] ?? 'desconocido',
$wp_error->get_error_message()
);
error_log( $log_line, 3, WP_CONTENT_DIR . '/logs/mail-errors.log' );
}
Con esto, cada fallo queda registrado con fecha, destinatario y motivo real (SMTP rechazado, credenciales mal, servidor caído...). Ya no dependes de que el cliente te avise — tú te enteras primero.
Importante: esa carpeta /logs/ tiene que estar protegida (un .htaccess con deny from all, o fuera de la raíz pública) para que nadie acceda a esos datos desde fuera.
¿Y si el fallo es en JavaScript?
Aquí cambia la naturaleza del problema. El JS corre en el navegador del usuario, no en tu servidor — así que si se rompe un carrito AJAX, un formulario multistep o un slider, tú no ves nada. El error vive y muere en el ordenador de tu cliente, y jamás te enteras.
JavaScript no puede escribir directamente en un archivo del servidor, pero sí puede avisar al servidor de que algo ha fallado. El sistema de log sigue siendo el mismo (PHP escribiendo en el mismo log); lo único que cambia es cómo llega la información hasta ahí.
Paso 1: capturar el error en el navegador
window.addEventListener('error', function (event) {
reportarError({
mensaje: event.message,
archivo: event.filename,
linea: event.lineno,
url: window.location.href
});
});
window.addEventListener('unhandledrejection', function (event) {
reportarError({
mensaje: event.reason?.message || 'Promesa rechazada',
url: window.location.href
});
});
function reportarError(datos) {
fetch('/wp-json/i8/v1/log-error', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(datos)
});
}
Paso 2: recibirlo en PHP y unificarlo con el resto de logs
add_action( 'rest_api_init', function () {
register_rest_route( 'i8/v1', '/log-error', [
'methods' => 'POST',
'callback' => 'i8_log_js_error',
'permission_callback' => '__return_true',
]);
});
function i8_log_js_error( WP_REST_Request $request ) {
$data = $request->get_json_params();
$log_line = sprintf(
"[%s] JS FALLIDO | URL: %s | Error: %s\n",
current_time( 'mysql' ),
$data['url'] ?? 'desconocida',
$data['mensaje'] ?? 'sin detalle'
);
error_log( $log_line, 3, WP_CONTENT_DIR . '/logs/js-errors.log' );
return new WP_REST_Response( [ 'ok' => true ], 200 );
}
Resultado: un único punto donde caen los fallos, vengan del servidor (email, conexión, pago) o del navegador de un cliente al otro lado del mundo. No importa dónde nace el problema — todo termina en el mismo sitio donde tú vas a mirar primero.
Por qué esto ahorra dinero de verdad
Sin logs, diagnosticar un fallo intermitente puede llevar horas: reproducir el error, preguntar al cliente qué hizo exactamente, probar en distintos navegadores... Con un log bien diseñado, el tiempo de diagnóstico baja de horas a minutos. Y en un negocio, tiempo de resolución = dinero: menos horas facturadas en debugging, menos pedidos perdidos, menos clientes enfadados esperando una respuesta que no llega.
Diseñar el software asumiendo que algo va a salir mal no es pesimismo — es la diferencia entre "no sé qué ha pasado" y "esto pasó a las 14:32, aquí está el motivo, ya está arreglado". Esa frase, dicha en cinco minutos en vez de en tres días, es la que hace que un cliente confíe en seguir trabajando contigo.