No puedo obtener un objeto JSON en respuesta a una solicitud Ajax con wp_ajax
Tengo un problema con WordPress y Ajax.
Esta es mi parte de JavaScript (la recorté un poco):
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) );
});
Mi código PHP es el siguiente:
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' );
El script obtiene la respuesta Ajax desde admin-ajax. Desafortunadamente, la consola arroja un error cuando llega a la instrucción each
en el código JavaScript... dice:
"Uncaught TypeError: Cannot use 'in' operator to search for '4' in Array".
Si hago un console.log de mi variable "posts" obtengo un string 'Array'. No importa cómo pase la variable $list
en PHP, siempre devolverá una cadena. La consulta devuelve posts en otras partes, así que no está vacía. Intenté sin json_encode
, con y sin declarar el encabezado, usando wp_send_json()
, poniendo ob_clean()
antes de mostrar el array, poniendo el array dentro de otro array... Pero siempre llega a ajax
como una cadena Array
y each
no puede recorrerlo.
Esto debería ser algo muy simple y no puedo entender por qué no está funcionando. No tengo otros errores o advertencias de JavaScript o PHP y todo lo demás funciona bien.

La respuesta de BODA82 ayudó, pero eventualmente me di cuenta de que debería haber reemplazado responseText
con el método responseJSON
en mi código JavaScript. En el ejemplo a continuación estaba almacenando los resultados de la respuesta Ajax en una variable. No sabía que existía un método específico para obtener la respuesta en JSON. De esta manera, el objeto/array con los resultados de get_posts()
se devuelve correctamente y no como una cadena de texto:
posts = $.ajax({
type: 'GET',
url: ajaxurl,
async: false,
dataType: 'json',
data: { action : 'getHotelsList' },
done: function(results) {
// Mmm, ¿quizás ni siquiera necesito esto?
JSON.parse(results);
return results;
},
fail: function( jqXHR, textStatus, errorThrown ) {
console.log( 'No se pudieron obtener las publicaciones, respuesta del servidor: ' + textStatus + ': ' + errorThrown );
}
}).responseJSON; // <-- esto en lugar de .responseText
Nota para mí mismo, pero también un consejo general: si no puedes arreglar algo por la noche, es señal de que deberías irte a la cama, leer un libro y contar estrellas. La respuesta se encontrará a la mañana siguiente, mientras más temprano, mejor :D

Casi listo con tu función PHP. No es necesario establecer el encabezado. (Edición: También, asumiendo que get_posts()
realmente está devolviendo resultados.)
function myAjaxFunc() {
$posts = get_posts( array(
'posts_per_page' => -1, // Obtener todos los posts
'orderby' => 'title', // Ordenar por título
'order' => 'ASC', // Orden ascendente
'post_type' => 'my-post-type', // Tipo de post personalizado
'post_status' => array( 'publish', 'draft' ) // Estados de publicación
) );
$list = array();
foreach ( $posts as $post ) {
$list[] = array(
'id' => $post->ID, // ID del post
'name' => $post->post_title, // Título del post
'link' => get_permalink( $post->ID ), // Enlace permanente
);
}
echo json_encode( $list );
die;
}
add_action( 'wp_ajax_nopriv_myAjaxFunc', 'myAjaxFunc' ); // Para usuarios no logueados
add_action( 'wp_ajax_myAjaxFunc', 'myAjaxFunc' ); // Para usuarios logueados
Y tu 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('No se pueden recuperar los datos.');
}
});
