Aceptar llamada AJAX con datos de formulario serializados
Estoy tratando de pasar datos de un formulario a un plugin de WordPress a través de ajax y funciona bien, excepto cuando los datos del formulario están serializados, entonces el servidor responde con un mensaje de error. Llevo días atascado con esto, pero no logro que funcione. ¿Qué estoy haciendo mal? No puede ser tan difícil, ¿verdad?
Aquí está el mensaje de error:
call_user_func_array() espera que el parámetro 1 sea una callback válida, la función 'process_request' no se encuentra o el nombre de la función no es válido en X:\xampp\htdocs\testsite\wp-includes\plugin.php en la línea 406
La llamada AJAX:
jQuery(document).ready(function($) {
nonce: whatever
//si uso esta variable, funciona bien
var data = {action: 'process_request', add_my_data: 'whatever', 'my_data[name]':'whatever', my_nonce: nonce};
//si uso esta variable, el servidor devuelve el error anterior
//debido a que .serialize() no incluye el nombre del botón submit
//y el formulario no contiene el nombre de la función a llamar, los agregué manualmente a la cadena. nonce se obtiene del formulario.
var data2 ='action=process_request&add_my_data=whatever&' + $('#my-form').serialize();
$('.my_submit_button').click(function(event) {
event.preventDefault();
jQuery.ajax({
type : 'post',
url : ajaxurl,
timeout: 25000,
data : //data (funciona) o data2 (no funciona),
[...]
Lo extraño es que los datos POST para 'data2' parecen estar bien y tienen la misma sintaxis que 'data'.
Controlé los datos POST con firebug:
para 'data':
action=process_request&add_my_data=whatever&my_data%5Bname%5D=whatever&my_nonce=1b444dd703
para 'data2' (con el formulario serializado, la única diferencia que veo es el referrer):
action=process_request&add_my_data=whatever&my_data%5Bname%5D=whatever&my_nonce=1b444dd703&_wp_http_referer=%2Ftestsite%2Fadmin%2Ftestpage%2F
La función PHP que maneja la solicitud:
function process_request() {
//validación de nonce omitida para mejor legibilidad
if( isset ($_POST['add_my_data']) ) {
$this->add_info_array('placeholder', 'Base de datos actualizada');
}
//hacer algunas cosas aquí
die();
}
add_action('wp_ajax_process_request', 'process_request');
ACTUALIZACIÓN: El problema es el referrer en la cadena que se crea para 'data2'. Revisa mi comentario abajo.

Cuando trabajo con AJAX y Formularios en WordPress, me gusta codificar la acción AJAX directamente en el formulario para que la serialización funcione sin problemas. De hecho, escribí un artículo sobre esto el año pasado: https://webdevstudios.com/2015/02/12/handling-ajax-in-wordpress/
Pero estás aquí por respuestas, no por un artículo de blog, así que aquí está la parte resumida. Tienes tres partes aquí: primero está el formulario HTML. Puedes aprovechar serialize()
colocando la acción en un campo oculto del formulario, aquí un ejemplo:
<form class="my_form">
<?php wp_nonce_field( 'my_action_nonce' ); ?>
<input type="hidden" name="action" value="my_action" />
<!-- Más campos aquí... -->
<input type="submit" name="submit" value="Enviar" class="submit_form_btn" />
</form>
Observa el campo oculto llamado action
. Por supuesto, mantuve wp_nonce_field()
ya que, bueno, problemas de seguridad.
La segunda parte es el jQuery real. Como se mencionó antes, no necesitas acceder a AJAX a través del objeto jQuery original ya que ya lo pasaste como $
, pero en realidad no hace daño, solo es mala práctica.
jQuery( document ).ready( function( $ ) {
$( '.submit_form_btn' ).on( 'click', function( evt ) {
// Detener el envío predeterminado del formulario
evt.preventDefault();
// Serializar todo el formulario, que incluye la acción
var serialized = $( '.my_form' ).serialize();
$.ajax( {
url: ajaxurl, // Esta variable está en algún lugar
method: 'POST',
data: serialized, // Aquí están nuestros datos serializados
} ).done( function( result ){
// Manejar el resultado aquí...
} );
} );
} );
Intenté comentar el código lo mejor que pude, debería tener más sentido, pero déjame explicar. Primero detienes el envío del formulario con el método preventDefault()
del objeto evt
(abreviatura de event).
Luego serializas los datos del formulario y los guardas en una variable. Supongo que podrías acortarlo y simplemente colocarlo directamente en el objeto data, pero eso depende de ti.
La parte final, bueno, necesitas ver lo que estás enviando, ¿verdad? Ahí es donde error_log
y print_r
son útiles, así es cómo:
<?php
function handle_ajax() {
// Aquí verificas tu nonce
if ( ! wp_verify_nonce( $_POST['_wpnonce'], 'my_action_nonce' ) ) {
// Puedes retornar o usar cosas ingeniosas con JSON
wp_send_json_error();
}
// Aquí deberías obtener TODOS tus datos en una variable $_POST
// o puedes hacer algo como esto y luego revisar tu registro de errores
error_log( print_r( $_POST, 1 ) );
// Esto imprimirá TODA la variable $_POST en tu debug.log si lo tienes
// habilitado; si no, va al registro de errores de PHP
}
add_action( 'wp_ajax_my_action', 'handle_ajax' );
Ahora eso DEBERÍA manejar tu AJAX por ti. Lo que hagas con los datos depende de ti.

¿Por qué estás usando jQuery.ajax
?
Cuando defines jQuery(document).ready(function($) {
... $
se convierte en tu variable global de jQuery.
Contenedor noConflict de jQuery en WordPress
Tu llamada AJAX debería parecerse a esto:
$.ajax({
type : 'post',
url : ajaxurl,
etc : ....
Además, no puedes simplemente pasar una cadena de variables. Primero necesitas definirlas en un objeto y pasar ese objeto.
Prueba esto:
get_data = $('#my-form').serialize();
var data = {action: 'process_request', add_my_data: get_data, my_nonce: nonce};
No estoy seguro sobre el serializado... ya que pensé que WordPress ya hace eso durante el proceso de envío AJAX. Quizás necesites investigar más sobre eso.

Tenías razón sobre la variable de jQuery, pero no cambió nada, como dije, si no está serializado todo funciona perfectamente.
