Como usar AJAX en WordPress con admin-ajax.php en PHP y JS en WordPress

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

  1. Encolar script JS en el frontend con wp_enqueue_script.
  2. Pasar la URL de admin-ajax.php y un nonce al script con wp_localize_script o wp_add_inline_script.
  3. 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.
  4. 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).
  5. 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

  1. Validar y sanear siempre: usa sanitize_text_field, sanitize_email, esc_url_raw, intval, wp_kses_post para HTML esperado, etc.
  2. Comprobar capacidades: si la acción modifica datos sensibles, utiliza current_user_can() para evitar elevaciones de privilegios.
  3. Nonces: generan seguridad frente a CSRF usa check_ajax_referer en el servidor y envía el nonce desde el cliente.
  4. Evita outputs inesperados: no uses echo indiscriminadamente wp_send_json_ establece cabeceras correctas y finaliza la ejecución.
  5. 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).
  6. 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).
  7. Manejo de errores: devuelve mensajes y códigos HTTP correctos desde PHP, y muestra mensajes útiles en el cliente.
  8. 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 🙂



Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *