Aceptar llamada AJAX con datos de formulario serializados

20 oct 2013, 01:42:21
Vistas: 23.9K
Votos: 1

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.

6
Comentarios

Necesitas mostrar un poco más de código, ¿dónde está el hook?

brasofilo brasofilo
20 oct 2013 02:13:17

Está ahí, simplemente no lo incluí arriba (ahora está incluido). Como dije, la función y la llamada ajax funcionan, simplemente no funciona con los datos post serializados

JimQ JimQ
20 oct 2013 02:26:11

El mensaje de error dice que process_request() no está definida. ¿De dónde viene esa función?

kaiser kaiser
20 oct 2013 02:51:10

Esta función está en mi archivo de plugin.

JimQ JimQ
20 oct 2013 03:05:25

De acuerdo, el referer en la cadena que se crea para 'data2' parece ser el problema. Si reemplazo la parte serializada() con la cadena que obtuve de Firebug y quito el referer, de repente funciona. Si lo dejo incluido, mismo problema que describí. Entonces la nueva pregunta es: ¿Por qué el referer en la cadena hace que WordPress muestre ese mensaje de error y cómo puedo evitar que se incluya con serialize()? Ni siquiera es parte del formulario, ¿de dónde viene?

JimQ JimQ
20 oct 2013 15:53:47

Bien gente, nos estamos acercando: Estaba usando wp_nonce_field en el formulario, eso hace que WordPress cree un campo oculto con el referer, así que eso explica de dónde viene. Última pregunta pendiente: ¿Por qué el referer causa un problema?

JimQ JimQ
20 oct 2013 16:04:07
Mostrar los 1 comentarios restantes
Todas las respuestas a la pregunta 2
0

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.

11 ene 2016 06:56:34
3

¿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.

20 oct 2013 02:45:38
Comentarios

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

JimQ JimQ
20 oct 2013 03:14:45

Lo siento, este fue el primer comentario, ya no pude editarlo:

JimQ JimQ
20 oct 2013 03:21:03

Gracias por la sugerencia, pero si hago eso, los datos serializados() se definirán como el valor de add_my_data. Así: add_my_data:action=process_request&add_my_data=whatever&...

JimQ JimQ
20 oct 2013 03:21:26