Не могу получить объект JSON в ответе на Ajax-запрос с wp_ajax
У меня проблема с WordPress и Ajax.
Вот моя часть JavaScript (я немного её сократил):
var posts = $.ajax({
type: 'POST',
url: ajaxurl,
async: false,
dataType: 'json',
data: { action: 'myAjaxFunc' },
done: function(response) {
return response;
}
}).responseText;
$.each(posts, function() {
$('#someSelect').append( $('<option</option>').text(this.name).val(this.id) );
});
Мой PHP-код выглядит следующим образом:
function myAjaxFunc() {
$posts = get_posts( array(
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
'post_type' => 'my-post-type',
'post_status' => array( 'publish', 'draft' )
) );
$list = array();
foreach ( $posts as $post ) {
$list[] = array(
'id' => $post->ID,
'name' => $post->post_title,
'link' => get_permalink( $post->ID ),
);
}
header("Content-type: application/json");
echo json_encode( $list );
die;
}
add_action( 'wp_ajax_nopriv_myAjaxFunc', 'myAjaxFunc' );
add_action( 'wp_ajax_myAjaxFunc', 'myAjaxFunc' );
Скрипт получает Ajax-ответ от admin-ajax. К сожалению, консоль выдает ошибку, когда доходит до выражения each
в JavaScript коде... в ней говорится:
"Uncaught TypeError: Cannot use 'in' operator to search for '4' in Array".
Если я сделаю console.log моей переменной "posts", я получу строку 'Array'. Независимо от того, как я передаю переменную $list
в PHP, она всегда возвращает строку. Запрос возвращает записи в других местах, так что он не пустой. Я пробовал без json_encode
, с объявлением заголовка и без, используя wp_send_json()
, вставляя ob_clean()
перед выводом массива, помещая массив в массив... Но он всегда приходит в ajax
как строка Array
, и each
не может перебирать его.
Это должно быть очень простой вещью, и я не могу понять, почему это не работает. У меня нет других ошибок или предупреждений JavaScript или PHP, и всё остальное работает нормально.

Ответ BODA82 помог, но в итоге я понял, что должен был заменить метод responseText
на responseJSON
в моём JavaScript коде. В примере ниже я сохранял результаты Ajax-ответа в переменную. Я не знал, что существует специальный метод для получения ответа в формате JSON. Таким образом объект/массив с результатами get_posts()
возвращается корректно, а не как строка:
posts = $.ajax({
type: 'GET',
url: ajaxurl,
async: false,
dataType: 'json',
data: { action : 'getHotelsList' },
done: function(results) {
// Хм, возможно это мне даже не нужно?
JSON.parse(results);
return results;
},
fail: function( jqXHR, textStatus, errorThrown ) {
console.log( 'Не удалось получить посты, ответ сервера: ' + textStatus + ': ' + errorThrown );
}
}).responseJSON; // <-- это вместо .responseText
Заметка для себя, но также общий совет: если вы не можете что-то исправить вечером, это знак, что вам следует лечь спать, почитать книгу и посчитать звёзды. Ответ найдётся на следующее утро, чем раньше, тем лучше :D

Почти готово с вашей PHP-функцией. Нет необходимости устанавливать заголовок. (Примечание: также предполагается, что get_posts()
действительно возвращает результаты.)
function myAjaxFunc() {
$posts = get_posts( array(
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
'post_type' => 'my-post-type',
'post_status' => array( 'publish', 'draft' )
) );
$list = array();
foreach ( $posts as $post ) {
$list[] = array(
'id' => $post->ID,
'name' => $post->post_title,
'link' => get_permalink( $post->ID ),
);
}
echo json_encode( $list );
die;
}
add_action( 'wp_ajax_nopriv_myAjaxFunc', 'myAjaxFunc' );
add_action( 'wp_ajax_myAjaxFunc', 'myAjaxFunc' );
И ваш JavaScript:
$.ajax({
url: "<?php bloginfo('url'); ?>/wp-admin/admin-ajax.php",
type: "POST",
data: "action=myAjaxFunc",
success: function(results) {
var posts = JSON.parse(results);
console.log(results);
$.each(posts, function() {
$('#someSelect').append( $('<option></option>').text(this.name).val(this.id) );
});
},
error: function() {
console.log('Не удалось получить данные.');
}
});

Есть выход. Используйте complete
вместо success
или done
:
posts = $.ajax({
type: 'GET',
url: ajaxurl,
async: false,
dataType: 'json',
data: { action : 'getHotelsList' },
complete: function(results) {
И попробуйте убрать async:false
, если проблема не исчезнет.
