Pulsa ESC para cerrar

Curso WordpressCurso Wordpress

admin-ajax.php dispara la CPU: cómo descubrir quién lo usa y ponerle orden

admin-ajax.php es el archivo por el que pasan muchas peticiones «en segundo plano» de WordPress: el autoguardado, el Heartbeat, filtros de productos, formularios que se envían sin recargar, contadores de visitas, chats. Cada una de esas peticiones carga WordPress completo, con todos sus plugins. Por eso, cuando son muchas, la CPU se dispara.

El archivo en sí está bien. Lo que hay que averiguar es qué acciones lo están llamando y quién.

No bloquees admin-ajax.php por completo. Romperías el editor, WooCommerce, formularios y muchas funciones del escritorio. La solución es reducir lo que sobra.

Paso 1: mirar desde el navegador

Abre una página del sitio (sin sesión iniciada, en una ventana de incógnito), presiona F12, ve a la pestaña Red y escribe admin-ajax en el filtro. Deja la página abierta un par de minutos.

Si ves peticiones que se repiten solas cada pocos segundos, ya tienes un sospechoso. Haz clic en una y mira en Carga útil (Payload) el valor de action: es el nombre de la acción.

Paso 2: contar las acciones en el servidor

Para ver el panorama completo, incluidas las peticiones de robots y del escritorio, este mu-plugin cuenta cuántas veces se llama cada acción por hora. Es una herramienta de diagnóstico: déjala uno o dos días y luego bórrala.

Guárdalo como wp-content/mu-plugins/cwp-contar-ajax.php:

<?php
/**
 * Plugin Name: Contador de admin-ajax (diagnóstico temporal)
 */

add_action( 'admin_init', function () {
	if ( ! wp_doing_ajax() ) {
		return;
	}
	$accion = isset( $_REQUEST['action'] ) ? sanitize_key( wp_unslash( $_REQUEST['action'] ) ) : '(sin-accion)';
	$quien  = is_user_logged_in() ? 'con-sesion' : 'visitante';
	$clave  = 'cwp_ajax_' . gmdate( 'YmdH' );
	$conteo = get_transient( $clave ) ?: array();
	$conteo[ $quien . ':' . $accion ] = ( $conteo[ $quien . ':' . $accion ] ?? 0 ) + 1;
	set_transient( $clave, $conteo, 2 * DAY_IN_SECONDS );
}, 1 );

Para ver el resultado de una hora (la hora va en UTC, cuatro horas más que la de Chile continental en horario de invierno y tres en verano):

wp transient get cwp_ajax_2026102715 --format=json

Ordena mentalmente de mayor a menor: la acción que aparece miles de veces es la que hay que atender.

Paso 3: encontrar el plugin responsable

Cada acción de AJAX se registra con un hook que lleva su nombre: wp_ajax_NOMBRE (con sesión) y wp_ajax_nopriv_NOMBRE (visitantes). Búscalo en tus plugins y tema:

grep -rl "wp_ajax_nopriv_cwp_filtro_productos" wp-content/plugins wp-content/themes

El resultado te dice qué plugin o tema la registra.

Paso 4: reducir la carga

Según lo que encuentres:

  • heartbeat con miles de llamadas: viene de pestañas del escritorio abiertas. Redúcelo como vimos en la guía del escritorio lento.
  • Un contador de visitas o estadísticas que registra cada página con AJAX: busca la opción de usar la API REST, un método sin AJAX o desactiva esa función si ya usas otra analítica.
  • Un filtro de productos o una búsqueda en vivo: revisa sus ajustes (muchos permiten usar URLs con caché en lugar de AJAX) y protégelo de robots, que suelen recorrer todas las combinaciones de filtros.
  • Un plugin de chat, notificaciones o «visitantes en vivo» que consulta cada pocos segundos: aumenta el intervalo o reemplázalo.
  • Acciones de visitantes que llegan sin parar desde pocas IPs: son robots. Usa una regla de límite de velocidad en Cloudflare para /wp-admin/admin-ajax.php (por ejemplo, más de 30 peticiones por minuto desde una misma IP → desafío).

WooCommerce usa su propio punto de entrada (?wc-ajax=) para el carrito, así que esas peticiones no aparecen en admin-ajax.php. Si el problema está en la tienda, revisa también las peticiones con wc-ajax en la pestaña Red.

No olvides borrar el contador

Cuando termines el diagnóstico, elimina cwp-contar-ajax.php. Escribir un transitorio en cada petición también tiene un costo.

¿Encontraste una acción con miles de llamadas y no sabes de qué plugin es? Comparte su nombre en el foro y lo averiguamos.