I have a problem with WordPress and ajax.

This is my javascript part (I trimmed it a bit):

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) );
});

My PHP code is as follows:

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' );

The script gets the ajax response from admin-ajax. Unfortunately the console throws an error when it gets to the each statement in javascript... it says:

"Uncaught TypeError: Cannot use 'in' operator to search for '4' in Array". 

If I do a console.log of my "posts" var I get a string 'Array'. No matter how I pass the $list variable in PHP it will always return a string. The query returns posts elsewhere, so it's not empty. I tried without json_encode, with and without declaring header, using wp_send_json(), putting ob_clean() before echoing the array, putting the array into an array... But it always gets into ajax as a string Array and each cannot cycle through it.

This should be a very simple thing and I can't understand why it's not working. I don't have other javascript or php errors or warnings and everything else runs fine. I'm calling it a day and getting to sleep while posting this on stack :)

  • What do you see when you go to example.com/wp-admin/admin-ajax.php?action=myAjaxFunc – czerspalace Nov 17 '14 at 20:09
  • Any progress on your question? Could you please follow up? – kaiser Apr 15 '15 at 11:27
  • oh... this is from 5 months ago... I did answer to my own question by the way the next day I posted it, using bits of BODA82 answer - I just didn't marked it as the correct answer; @toscho added his follow up much later yesterday I can't verify if his answer is also good now, it makes sense though – unfulvio Apr 16 '15 at 21:13
up vote 5 down vote accepted

@BODA82 answer helped, but eventually I realized that I should have replaced responseText with responseJSON method in my javascript code. In the example below I was storing the ajax response results in a variable. I didn't know there was a specific method to get response in JSON. In such way the object/array with get_posts() results is returned correctly and not as a string:

posts = $.ajax({
    type: 'GET',
    url: ajaxurl,
    async: false,
    dataType: 'json',
    data: { action : 'getHotelsList' },
    done: function(results) {
        // uhm, maybe I don't even need this?
        JSON.parse(results);
        return results;
    },
    fail: function( jqXHR, textStatus, errorThrown ) {
        console.log( 'Could not get posts, server response: ' + textStatus + ': ' + errorThrown );
    }
}).responseJSON; // <-- this instead of .responseText

Note to self but also general advice: if you can't fix something in the evening it's a sign you should go to bed, read a book, count stars. Answer will be found the next morning, the earlier the better :D

Almost there with your PHP function. No need to set the header. (Edit: Also, assuming get_posts() is actually returning results.)

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' );

And your 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('Cannot retrieve data.');
    }
});

There is a way out, use complete instead of success or done

posts = $.ajax({
    type: 'GET',
    url: ajaxurl,
    async: false,
    dataType: 'json',
    data: { action : 'getHotelsList' },
    complete: function(results) {

and try to remove async:false if problem persists

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.