Принятие AJAX-запроса с сериализованными данными формы
Я пытаюсь передать плагину 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'. Проверьте мой комментарий ниже.
При работе с 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-запрос. Что делать с данными — решать вам.

Почему вы используете 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-запроса. Возможно, вам нужно изучить этот вопрос подробнее.

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