Contents
Introducción: ¿qué es admin-ajax.php y por qué usarlo?
admin-ajax.php es el punto de entrada clásico de WordPress para peticiones AJAX en instalaciones normales. Permite a JavaScript del lado cliente comunicarse con código PHP del servidor, ejecutando callbacks registrados mediante los hooks wp_ajax_{action} y wp_ajax_nopriv_{action}. Aunque hoy existen alternativas (por ejemplo la REST API), admin-ajax.php sigue siendo útil por su simplicidad y compatibilidad con plugins y temas existentes.
Ventajas y limitaciones
- Ventajas: integración simple con WP, manejo de permisos vía hooks diferentes para usuarios autenticados y no autenticados, helpers como wp_send_json_success.
- Limitaciones: carga relativamente pesada (se carga el entorno administrativo completo), no es ideal para peticiones de alta frecuencia para APIs públicas y de alto rendimiento conviene valorar la REST API.
Flujo básico de una petición AJAX con admin-ajax.php
- Encolar script JS en el frontend con wp_enqueue_script.
- Pasar la URL de admin-ajax.php y un nonce al script con wp_localize_script o wp_add_inline_script.
- Desde el cliente enviar una petición POST (o GET) a admin-ajax.php incluyendo el parámetro action con el nombre de la acción registrada.
- Registrar el callback PHP usando add_action(wp_ajax_{action}, mi_callback) y, si se necesita para usuarios no autenticados, add_action(wp_ajax_nopriv_{action}, mi_callback).
- En el callback validar seguridad (check_ajax_referer), sanear entradas, procesar, y devolver respuesta con wp_send_json_success() o wp_send_json_error().
Resumen de hooks comunes
Hook | Propósito |
---|---|
wp_ajax_mi_accion | Manejador para usuarios autenticados |
wp_ajax_nopriv_mi_accion | Manejador para usuarios no autenticados |
Ejemplo completo paso a paso
1) Encolar el script y pasar ajax_url nonce
Añade este código en functions.php o en el archivo principal del plugin. Se usa wp_localize_script para inyectar la URL de admin-ajax.php y un nonce para seguridad.
admin_url(admin-ajax.php), nonce => wp_create_nonce(mi_nonce) )) } add_action(wp_enqueue_scripts, tema_enqueue_ajax_scripts) ?>
2) HTML simple del frontend (formulario)
3) JavaScript con jQuery (ejemplo clásico)
jQuery(document).ready(function(){ (#mi-boton).on(click, function(e){ e.preventDefault() var data = { action: mi_accion, // nombre de la acción security: mi_ajax_obj.nonce, // nonce enviado desde PHP param: (#mi-input).val() // datos que quieras enviar } .post(mi_ajax_obj.ajax_url, data, function(response){ if(response.success){ (#resultado).text(response.data.received / response.data.time) } else { (#resultado).text(Error: (response.data response.data.message ? response.data.message : respuesta no válida)) } }, json).fail(function(jqXHR, textStatus){ (#resultado).text(AJAX fallo: textStatus) }) }) })
3b) JavaScript moderno con Fetch (vanilla JS)
document.getElementById(mi-boton).addEventListener(click, function(e){ e.preventDefault() var formData = new FormData() formData.append(action, mi_accion) formData.append(security, mi_ajax_obj.nonce) formData.append(param, document.getElementById(mi-input).value) fetch(mi_ajax_obj.ajax_url, { method: POST, credentials: same-origin, body: formData }) .then(function(response){ return response.json() }) .then(function(data){ if(data.success){ document.getElementById(resultado).textContent = data.data.received / data.data.time } else { document.getElementById(resultado).textContent = Error: (data.data data.data.message ? data.data.message : respuesta no válida) } }) .catch(function(error){ document.getElementById(resultado).textContent = Fetch error: error }) })
4) Callback PHP que procesa la petición
Sin permisos), 403) // } // Procesado: ejemplo simple resultado = array( received => param, time => current_time(mysql) ) // Devuelve JSON con éxito wp_send_json_success(resultado) // wp_send_json_ ya finaliza la ejecución, pero si lo prefieres: // wp_die() } add_action(wp_ajax_mi_accion, mi_ajax_handler) add_action(wp_ajax_nopriv_mi_accion, mi_ajax_handler) ?>
Errores comunes y cómo solucionarlos
- 404 al llamar admin-ajax.php: asegúrate de usar admin_url(admin-ajax.php) y que no haya reglas de .htaccess bloqueando admin-ajax.php.
- Respuesta vacía: revisa el Network en DevTools, activa WP_DEBUG_LOG o pon logs en el callback. Evita que otros echo/print afecten la salida JSON.
- Nonce inválido: el nonce puede expirar (por defecto 24 horas). Verifica que envías el mismo nonce creado antes de renderizar el formulario y que el parámetro coincida con el nombre usado en check_ajax_referer.
- Problemas con usuarios no autenticados: recuerda registrar la acción también con wp_ajax_nopriv_{action}.
Ejemplo de manejo de errores en PHP
Parámetro vacío), 400) } // ... resto del procesado ... } add_action(wp_ajax_mi_accion, mi_ajax_handler_error) add_action(wp_ajax_nopriv_mi_accion, mi_ajax_handler_error) ?>
Enviar archivos mediante AJAX
Para subir archivos usa FormData en el cliente y wp_handle_upload en el servidor. Es necesario incluir test_form => false en wp_handle_upload porque la subida viene por AJAX, no por un formulario HTML tradicional.
// Cliente: envío de archivo con Fetch var fd = new FormData() fd.append(action, mi_subir) fd.append(security, mi_ajax_obj.nonce) fd.append(file, document.getElementById(file-input).files[0]) fetch(mi_ajax_obj.ajax_url, { method: POST, credentials: same-origin, body: fd }) .then(res => res.json()) .then(data => console.log(data)) .catch(err => console.error(err))
false)) if ( isset(uploaded[error]) ) { wp_send_json_error(uploaded[error]) } // Si quieres adjuntar al media library: // require_once(ABSPATH . wp-admin/includes/media.php) // require_once(ABSPATH . wp-admin/includes/image.php) // attachment_id = media_handle_sideload(file_array, 0) wp_send_json_success(uploaded) } add_action(wp_ajax_mi_subir, mi_ajax_subir) add_action(wp_ajax_nopriv_mi_subir, mi_ajax_subir) ?>
Buenas prácticas, rendimiento y seguridad
- Validar y sanear siempre: usa sanitize_text_field, sanitize_email, esc_url_raw, intval, wp_kses_post para HTML esperado, etc.
- Comprobar capacidades: si la acción modifica datos sensibles, utiliza current_user_can() para evitar elevaciones de privilegios.
- Nonces: generan seguridad frente a CSRF usa check_ajax_referer en el servidor y envía el nonce desde el cliente.
- Evita outputs inesperados: no uses echo indiscriminadamente wp_send_json_ establece cabeceras correctas y finaliza la ejecución.
- Caching y throttling: para consultas caras, cachea resultados con transients y considera limitar la frecuencia de peticiones (debounce en inputs, rate limiting con transient por IP).
- Alternativa REST API: para endpoints públicos o de alto rendimiento, valora usar la REST API de WordPress (menor overhead y mejor manejo de cachés).
- Manejo de errores: devuelve mensajes y códigos HTTP correctos desde PHP, y muestra mensajes útiles en el cliente.
- Evitar consultas pesadas en cada petición: paginar, limitar campos y usar índices adecuados en la base de datos.
Depuración y diagnóstico
- Usa la pestaña Network de devtools para inspeccionar la petición y la respuesta (payload, headers, response).
- Activa WP_DEBUG y WP_DEBUG_LOG para ver errores en el servidor.
- Si la respuesta contiene HTML adicional (warnings, notices), comprueba plugins o temas que impriman contenido inesperado. Desactiva temporalmente para aislar el problema.
Conclusión y recomendaciones
admin-ajax.php sigue siendo una forma rápida y directa para implementar AJAX en WordPress. Sigue las buenas prácticas: encola scripts correctamente, usa nonces y capacidades, sanea entradas y usa wp_send_json_ para respuestas consistentes. Para cargas altas o APIs públicas valora la REST API. Con estos patrones tendrás implementaciones seguras, fáciles de depurar y mantenibles.
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |