Принятие AJAX-запроса с сериализованными данными формы

20 окт. 2013 г., 01:42:21
Просмотры: 23.9K
Голосов: 1

Я пытаюсь передать плагину WordPress данные формы через ajax, и всё работает нормально, пока данные формы не сериализованы. В случае сериализации сервер отвечает сообщением об ошибке. Я застрял с этим на несколько дней и не могу заставить это работать. Что я делаю неправильно? Это ведь не должно быть так сложно, верно?

Вот сообщение об ошибке:

call_user_func_array() expects parameter 1 to be a valid callback, function 'process_request' not found or invalid function name in X:\xampp\htdocs\testsite\wp-includes\plugin.php on line 406

AJAX-запрос:

jQuery(document).ready(function($) {

nonce: whatever

// если использовать эту переменную, всё работает нормально 
var data = {action: 'process_request', add_my_data: 'whatever', 'my_data[name]':'whatever', my_nonce: nonce};

// если использовать эту переменную, сервер возвращает ошибку выше
// поскольку .serialize() не включает имя кнопки отправки
// и форма не содержит имени функции, которую нужно вызвать, я добавил их вручную в строку. nonce берется из формы.

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 (работает) или data2 (не работает),
[...]

Странно то, что POST-данные для 'data2' выглядят правильно и имеют тот же синтаксис, что и для 'data'.

Я проверил POST-данные с помощью Firebug:

для 'data':

action=process_request&add_my_data=whatever&my_data%5Bname%5D=whatever&my_nonce=1b444dd703 

для 'data2' (с сериализованной формой, единственное отличие, которое я вижу - это referer):

action=process_request&add_my_data=whatever&my_data%5Bname%5D=whatever&my_nonce=1b444dd703&_wp_http_referer=%2Ftestsite%2Fadmin%2Ftestpage%2F

PHP-функция, которая обрабатывает запрос:

function process_request() {

    // проверка nonce опущена для читаемости

    if( isset ($_POST['add_my_data']) ) {
        $this->add_info_array('placeholder', 'База данных обновлена');
    }
            // выполнить некоторые действия здесь
            die();
        }
      add_action('wp_ajax_process_request', 'process_request');

ОБНОВЛЕНИЕ: Проблема в referer в строке, которая создается для 'data2'. Проверьте мой комментарий ниже.

6
Комментарии

Вам нужно показать больше кода. Где находится хук?

brasofilo brasofilo
20 окт. 2013 г. 02:13:17

Он там, я просто не включил его выше (добавил сейчас). Как я уже сказал, функция и AJAX-запрос работают, просто не получается с сериализованными (serialized()) данными POST

JimQ JimQ
20 окт. 2013 г. 02:26:11

Сообщение об ошибке говорит, что process_request() не определена. Откуда эта функция?

kaiser kaiser
20 окт. 2013 г. 02:51:10

Эта функция находится в файле моего плагина.

JimQ JimQ
20 окт. 2013 г. 03:05:25

Хорошо, проблема, кажется, в referer в строке, которая создается для 'data2'. Если я заменю serialized() часть строкой, которую получил из Firebug, и уберу referer, внезапно всё начинает работать. Если оставить referer, возникает та же проблема, что и описана. Итак, новый вопрос: Почему referer в строке заставляет WordPress выдавать это сообщение об ошибке, и как я могу предотвратить его включение в serialize()? Он даже не является частью формы, так откуда он берется?

JimQ JimQ
20 окт. 2013 г. 15:53:47

Ладно, народ, мы всё ближе к разгадке: я использовал wp_nonce_field в форме, и WordPress создает скрытое поле с referer, так что теперь понятно, откуда он берется. Остался последний вопрос: Почему referer вызывает проблему?

JimQ JimQ
20 окт. 2013 г. 16:04:07
Показать остальные 1 комментариев
Все ответы на вопрос 2
0

При работе с AJAX и формами в WordPress мне нравится добавлять ajax-действие прямо в форму, чтобы сериализация работала "из коробки". На самом деле, я писал об этом статью в прошлом году: https://webdevstudios.com/2015/02/12/handling-ajax-in-wordpress/

Но вы здесь за ответами, а не за статьей в блоге, поэтому вот краткая суть. У нас есть три части: первая — это HTML-форма. Вы можете воспользоваться serialize(), поместив действие в скрытое поле формы, вот пример:

<form class="my_form">
    <?php wp_nonce_field( 'my_action_nonce' ); ?>
    <input type="hidden" name="action" value="my_action" />
    <!-- Другие поля здесь... -->
    <input type="submit" name="submit" value="Отправить" class="submit_form_btn" />
</form>

Обратите внимание на скрытое поле формы с именем action. Конечно, я оставил wp_nonce_field(), потому что, ну, вопросы безопасности.

Вторая часть — это сам jQuery. Как уже упоминалось, вам не нужно обращаться к AJAX через оригинальный объект jQuery, так как он уже передан как $, но в целом это не навредит, просто не лучшая практика.

jQuery( document ).ready( function( $ ) {
    $( '.submit_form_btn' ).on( 'click', function( evt ) {
        // Останавливаем стандартную отправку формы
        evt.preventDefault();
        // Сериализуем всю форму, включая действие
        var serialized = $( '.my_form' ).serialize();
        $.ajax( {
            url: ajaxurl, // Эта переменная где-то определена
            method: 'POST',
            data: serialized, // Здесь наши сериализованные данные
        } ).done( function( result ) {
            // Обрабатываем результат здесь...
        } );
    } );
} );

Я постарался максимально прокомментировать код, он должен быть понятным, но давайте разберем. Сначала мы останавливаем отправку формы методом preventDefault() объекта evt (сокращение от event).

Затем сериализуем данные формы и сохраняем их в переменную. Думаю, можно было бы сократить и сразу передать их в объект данных, но это уже на ваше усмотрение.

И последняя часть — вам же нужно видеть, что вы отправляете, верно? Здесь пригодятся error_log и print_r, вот как это сделать:

<?php

function handle_ajax() {
    // Проверяем nonce
    if ( ! wp_verify_nonce( $_POST['_wpnonce'], 'my_action_nonce' ) ) {
        // Можно либо просто завершить, либо использовать JSON
        wp_send_json_error();
    }
    // Здесь вы получите все данные в переменной $_POST
    // Или можно сделать так и проверить лог ошибок
    
    error_log( print_r( $_POST, 1 ) );

    // Это выведет ВСЮ переменную $_POST в debug.log, если он включен,
    // иначе — в лог ошибок PHP

}
add_action( 'wp_ajax_my_action', 'handle_ajax' );

Теперь это ДОЛЖНО обработать ваш AJAX-запрос. Что делать с данными — решать вам.

11 янв. 2016 г. 06:56:34
3

Почему вы используете jQuery.ajax?

Когда вы определяете jQuery(document).ready(function($) {... $ становится вашей глобальной переменной jQuery. Обёртка noConflict для jQuery в WordPress

Ваш ajax-запрос должен выглядеть примерно так:

$.ajax({
type : 'post',
url : ajaxurl,
etc : ....

Далее, вы не можете просто передать строку переменных. Сначала вам нужно определить их в объект и передать его.

Попробуйте так:

get_data = $('#my-form').serialize();
var data = {action: 'process_request', add_my_data: get_data, my_nonce: nonce};

Не уверен насчёт сериализации... Кажется, WordPress уже делает это во время ajax-запроса. Возможно, вам нужно изучить этот вопрос подробнее.

20 окт. 2013 г. 02:45:38
Комментарии

Ты был прав насчёт переменной jQuery, но это ничего не изменило, как я уже говорил, если не сериализовать данные, то всё работает как часы.

JimQ JimQ
20 окт. 2013 г. 03:14:45

Извини, это был первый комментарий, уже не мог отредактировать:

JimQ JimQ
20 окт. 2013 г. 03:21:03

Спасибо за предложение, но если я так сделаю, сериализованные данные будут определены как значение add_my_data. Вот так: add_my_data:action=process_request&add_my_data=whatever&...

JimQ JimQ
20 окт. 2013 г. 03:21:26