Вопрос или проблема
Я пытался, пытался и пытался, я искал и искал… Я не могу понять, почему это не работает. Одна большая проблема в том, что я не могу выяснить, как получить хорошую информацию для отладки о том, почему это не удается.
В любом случае, у меня есть поле поиска для поиска библиотек на CDNJS.com (что работает). При выборе результата я хочу добавить данные этой библиотеки в свою пользовательскую таблицу WordPress. Этот процесс не удается, независимо от того, что я пробую.
Вот код:
<?php
function cdnjs_add_library_callback() {
// Получаем данные библиотеки из POST-запроса
$library = json_decode(file_get_contents('php://input'), true);
// Вставляем библиотеку в таблицу "cdnjs_libraries"
global $wpdb;
$table_name = $wpdb->prefix . 'cdnjs_libraries';
$wpdb->insert(
$table_name,
array(
'description' => $library['description'],
'homepage' => $library['homepage'],
'latest' => $library['latest'],
'license' => $library['license'],
'name' => $library['name'],
'version' => $library['version']
)
);
// Проверяем на наличие ошибок
if ($wpdb->last_error) {
die("Ошибка при вставке библиотеки: " . $wpdb->last_error);
}
// Возвращаем сообщение об успехе
echo "Библиотека успешно добавлена";
wp_die(); // это необходимо для немедленного завершения и возврата правильного ответа
}
add_action( 'wp_ajax_cdnjs_add_library', 'cdnjs_add_library_callback' );
?>
<div class="wrap">
<h1>Менеджер библиотек CDNJS</h1>
<p> </p>
<div id="search-form">
<form onsubmit="return false;">
<h2><label for="library-search">Поиск CDNJS</label></h2>
<input type="text" id="library-search" name="library-search" placeholder="Начните вводить для поиска..." size=30>
</form>
</div>
<p> </p>
<h2>Управляемые библиотеки</h2>
<table id="managed-libraries" class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>Действие</th>
<th>Имя файла</th>
<th>Описание</th>
<th>Версия</th>
<th>Лицензия</th>
<th>Домашняя страница</th>
<th>Удалить</th>
</tr>
</thead>
<tbody>
<?php echo generate_table_rows($managed_libraries); ?>
</tbody>
</table>
</div>
<script>
jQuery(document).ready(function($) {
// Настраиваем поле поиска как поле автозаполнения
$("#library-search").autocomplete({
// Устанавливаем источник параметров автозаполнения на API CDNJS
source: function(request, response) {
$.ajax({
data: {
search: request.term,
fields: "name,description,version,license,homepage"
},
success: function(results) {
console.log(results);
// Извлекаем список названий библиотек, описаний и URL из
// результатов и передаем их в коллбек ответа
var libraries = results.results.map(function(library) {
return {
label: "<b>"+library.name+"</b><br><i>"+library.description+"</i>",
value: library
};
});
response(libraries);
},
url: "https://api.cdnjs.com/libraries"
});
},
minLength: 3,
select: function(event, ui) {
// Когда библиотека выбрана из списка автозаполнения,
// добавляем эту библиотеку в таблицу "cdnjs_libraries" с помощью
// выполнения AJAX POST-запроса к PHP действию "cdnjs_add_library"
// Получаем выбранный объект библиотеки
var library = ui.item.value;
// Выполняем AJAX-запрос к действию "cdnjs_add_library"
$.ajax({
url: ajaxurl,
type: 'POST',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
action: 'cdnjs_add_library',
library: library
}),
success: function(response) {
console.log(response);
// Добавляем библиотеку в таблицу управляемых библиотек
$("#managed-libraries tbody").append(generateTableRow(library));
},
error: function(error) {
console.log(error);
}
});
}
}).autocomplete( "instance" )._renderItem = function( ul, library ) {
// Настраиваем отображение параметров автозаполнения
// Создаем новый элемент списка для библиотеки
var listItem = $("<li>");
// Создаем ссылку на библиотеку
var libraryLink = $("<a>", {
href: library.url,
target: "_blank",
html: library.label
});
// Добавляем ссылку в элемент списка
listItem.append(libraryLink);
// Возвращаем элемент списка
return listItem.appendTo(ul);
};
});
</script>
Чтобы уточнить мои комментарии, ваша проблема здесь:
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
action: 'cdnjs_add_library',
library: library
}),
При отправке данных на admin-ajax.php
, вам нужно установить свойство action
в data
на имя действия, например, cdnjs_add_library
. Вы этого не делаете здесь. data
не является объектом с свойством action
, как и ожидается, это строка, содержащая JSON, который случайно включает свойство action
. Это не одно и то же.
В исходном коде admin-ajax.php
вы увидите это:
$action = $_REQUEST['action'];
Если вы отправляете JSON на admin-ajax.php, $_REQUEST
не будет иметь свойства action
, по причинам, которые я объясняю здесь. Это означает, что ваше действие не будет выполнено, и ваш PHP-код не будет запущен.
Решение заключается в том, чтобы убрать contentType
и передать данные вот так:
data: {
action: 'cdnjs_add_library',
library: library
},
Ваша функция cdnjs_add_library_callback()
тогда должна установить $libary
следующим образом:
$library = $_POST['library'];
Ответ или решение
Ошибка 400 Bad Request при отправке JSON данных в admin-ajax.php WordPress
Проблема, с которой вы столкнулись, связана с некорректной отправкой данных в admin-ajax.php
вашего WordPress сайта, что, в свою очередь, вызывает ошибку 400 (Bad Request). Давайте разберёмся подробнее, что происходит, и как это исправить.
В чем проблема?
Когда вы используете jQuery для выполнения AJAX-запроса на admin-ajax.php
, важно правильно формировать данные, которые будете отправлять. В вашем коде вы используете следующий фрагмент для отправки данных:
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
action: 'cdnjs_add_library',
library: library
}),
Здесь вы устанавливаете contentType
в application/json
, и формируете данные как JSON-строку. Однако в admin-ajax.php
ожидается получение данных в формате application/x-www-form-urlencoded
или multipart/form-data
, что является стандартом для отправки POST-запросов в WordPress. Когда данные отправляются в формате JSON, это приводит к тому, что PHP не может разобрать их, и вы не получаете переменную $_REQUEST['action']
, что вызывает ошибку 400.
Как исправить проблему?
Для того чтобы ваша функция обработчика сработала корректно, вам нужно изменить способ передачи данных. Вместо того, чтобы сериализовать данные в JSON, отправьте их как объект:
$.ajax({
url: ajaxurl,
type: 'POST',
data: {
action: 'cdnjs_add_library',
library: library
},
success: function(response) {
console.log(response);
// Обновление таблицы управляемых библиотек
$("#managed-libraries tbody").append(generateTableRow(library));
},
error: function(error) {
console.log(error);
}
});
В этом случае сервер получит данные в формате, который он ожидает. Ваш серверный код также нужно немного изменить:
Обновите функцию обработчика PHP
Теперь вам нужно будет изменить, как вы получаете данные в вашем PHP обработчике:
function cdnjs_add_library_callback() {
// Получаем данные библиотеки из массива POST
$library = $_POST['library'];
// Проверяем, что переменная существует и не пуста
if (empty($library)) {
wp_send_json_error('Недостаточно данных для добавления библиотеки.'); // Возвращаем ошибку
}
// Извлекаем данные из массива библиотеки
global $wpdb;
$table_name = $wpdb->prefix . 'cdnjs_libraries';
$wpdb->insert(
$table_name,
array(
'description' => $library['description'],
'homepage' => $library['homepage'],
'latest' => $library['latest'],
'license' => $library['license'],
'name' => $library['name'],
'version' => $library['version']
)
);
// Проверяем на наличие ошибок
if ($wpdb->last_error) {
wp_send_json_error("Ошибка при добавлении библиотеки: " . $wpdb->last_error);
}
// Возвращаем сообщение об успешном добавлении
wp_send_json_success("Библиотека успешно добавлена");
}
add_action('wp_ajax_cdnjs_add_library', 'cdnjs_add_library_callback');
Вывод
Изменив способ отправки данных и добавив проверку на их наличие, вы сможете устранить ошибку 400 Bad Request при добавлении данных о библиотеках в вашу пользовательскую таблицу WordPress.
Если вы продолжаете сталкиваться с проблемами, рекомендуется использовать инструменты разработчика браузера для отслеживания и просмотра отправляемых запросов и ответов, которые могут дать вам дополнительную информацию о происходящем.