2

What would cause a basic get_posts() query to return an empty array during an Ajax function?

I have a front end page which loads a form. There is a dropdown which is populated when the page loads with some post titles. The same function that populates the select list values is called via Ajax when the value of another select list changes.

When the function is called via Ajax, the result is an empty array. When the page loads, the select list is fully populated.

By usingerror_log( var_export( $args, true ), 0 ); I have confirmed that the arguments passed to the function are the same on both page load and Ajax call and with error_log( var_export( $addons, true ), 0 ); I confirmed results on page load and an empty array on Ajax call. This also confirms execution of the correct function via Ajax.

/**
 * Retrieve all addons.
 *
 * @since   1.4
 * @param   arr         $args   Array of arguments. See @get_posts.
 * @return  arr|bool    Addons.
 */
function mh_get_addons( $args = array() )   {

    $defaults = array(
        'posts_per_page' => -1,
        'orderby'        => 'post_title',
        'order'          => 'DESC',
        'post_type'      => 'mh-addon',
        'post_status'    => 'publish'
    );

    $args = wp_parse_args( $args, $defaults );
    error_log( var_export( $args, true ), 0 );
    $addons = get_posts( $args );
    error_log( var_export( $addons, true ), 0 );
    return apply_filters( 'mh_get_addons', $addons );

} // mh_get_addons

Here is the Ajax function. As you can see I am passing no args here whilst testing so I would expect to see the same results I do on the initial page load.

function mh_update_form_addon_options() {

    $addons = mh_get_addons();

    if ( ! empty( $addons ) )   {
        $result['type']   = 'success';
        $result['addons'] = $addons;
    } else  {
        $result['type']   = 'success';
        $result['addons'] = 'No addons';
    }

    echo json_encode( $result );

    die();
} // mh_update_form_addon_options
add_action( 'wp_ajax_mh_update_form_addon_options', 'mh_update_form_addon_options' );
add_action( 'wp_ajax_nopriv_mh_update_form_addon_options', 'mh_update_form_addon_options' );

`

UPDATE The function is now returning results via the Ajax call when a user is logged in. However, if not logged in, no results. Strange thing is that the initial call to the mh_get_addons() function which is initiated on page load without ajax returns results regardless of whether or not a user is logged in...

6
  • Where exactly (theme/ plugin + hook) did you add and include this call? Sounds you are too early. Also please do a var_dump( __FUNCTION__ ); at the beginning of the callback to check if anything at all happens – check the console for output.
    – kaiser
    Aug 11, 2016 at 22:56
  • Sorry @kaiser which call/include are you referring to?
    – Mike
    Aug 11, 2016 at 23:31
  • This process is in an extension of another plugin. The core plugin registers the post type within the init hook. The extension's class is instantiated with the plugins_loaded hook. The page displayed is via a shortcode using add_shortcode. The shortcode instantiate's a further class within which a method is called and in that method I am using wp_enqueue_script() and wp_localize_script() for the JS file. The JS file waits for a change to be triggered on a form input field and then processes the call to ajax. I am seeing No Addons as the return
    – Mike
    Aug 11, 2016 at 23:44
  • If you make the ajax call return a hardcoded string does it always return that hardcoded string?
    – Tom J Nowell
    Aug 12, 2016 at 14:18
  • @TomJNowell - Yes. If my Ajax function simply contains echo json_encode( array( 'type' => 'success', 'addons' => 'Testing' ) ); die(); Testing is returned. Additionally, per the mh_update_form_addon_options() function above, I get No Addons if the get_posts() result is empty
    – Mike
    Aug 12, 2016 at 14:23

3 Answers 3

1

To get data from AJAX call you have to echo or print it. In WordPress you should use wp_send_json() function to send data as response to call.

function mh_get_addons( $args = array() )   {

    $defaults = array(
        'posts_per_page' => -1,
        'orderby'        => 'post_title',
        'order'          => 'DESC',
        'post_type'      => 'mh-addon',
        'post_status'    => 'publish'
    );

    $args = wp_parse_args( $args, $defaults );
    $addons = get_posts( $args );
    wp_send_json( apply_filters( 'mh_get_addons', $addons ) );

} // mh_get_addons
9
  • The function I have attached to the Ajax call handles that side of things. It calls the mh_get_addons() function and process the results. (when there are some!) The problem here is not that the data is not being returned, it is that the get_posts call is empty. Adding `error_log( var_export( $addons, true ), 0 ); // Confirms no results with Ajax, but results on initial load
    – Mike
    Aug 11, 2016 at 11:15
  • Try to remove wp_parse_args line and use $defaults in get_posts function. Does it change anything? Aug 11, 2016 at 11:18
  • Unfortunately not. Also confirmed $args is the same whether using Ajax or not
    – Mike
    Aug 11, 2016 at 11:50
  • Add this into your theme function.php file: add_action('wp_ajax_test', function() { wp_send_json(get_posts()); }); and go to address http://yourwebpage.com/wp-admin/admin-ajax.php?action=test. Does it show something? Aug 11, 2016 at 11:55
  • Just a 0 (zero)
    – Mike
    Aug 11, 2016 at 12:02
1

Instead of using the WP AJAX API, have you tried registering a REST endpoint? This assumes at least WP 4.5:

add_action( 'rest_api_init', function () {
    register_rest_route( 'mike/v1', '/addons/', array(
        'methods' => 'GET',
        'callback' => 'mh_update_form_addon_options',
    ) );
} );


function mh_update_form_addon_options( WP_REST_Request $data ) {

    $defaults = array(
        'posts_per_page'   => 200,
        'orderby'          => 'post_title',
        'order'            => 'DESC',
        'post_type'        => 'mh-addon',
        'post_status'      => 'publish',
        'suppress_filters' => false
    );

    $addons = get_posts( $args );
    $result = array();    
    if ( empty( $addons ) )   {
        return new WP_Error("No addons");
    }

    return $addons;
}

I've also simplified the function and eliminated some uncertainty by removing filters. I've also sped up the get_posts call by setting suppress_filters to false so that it caches the result. I've also added a maximum number, if you somehow ended up with 1 million addons this request would always fail, so always set an upper limit, even if it's a silly number you know it'll never reach

Keep in mind in a REST endpoint, we return what we're sending, we don't echo it, and use WP_Error for problems. You can adjust the register_rest_route call to mention arguments, see the WP API documentation for how.

Only WP Core is needed for this, no WP API plugin necessary

2
  • 1
    Actually right in the middle of registering API endpoints for all the custom post types the plugin creates so will give that a go
    – Mike
    Aug 12, 2016 at 14:46
  • 1
    In this day and age the WP AJAX api should be considered legacy, REST API endpoints are faster and more modern
    – Tom J Nowell
    Aug 12, 2016 at 14:46
0

Have you tried calling the global $post object at the top of your mh_get_addons() function?

function mh_get_addons( $args = array() )   {

  global $post;

  $defaults = array(
      'posts_per_page' => -1,
      'orderby'        => 'post_title',
      'order'          => 'DESC',
      'post_type'      => 'mh-addon',
      'post_status'    => 'publish'
  );

  $args = wp_parse_args( $args, $defaults );
  error_log( var_export( $args, true ), 0 );
  $addons = get_posts( $args );
  error_log( var_export( $addons, true ), 0 );
  return apply_filters( 'mh_get_addons', $addons );

  }

I'm not quite the wordpress expert yet, but had a similar issue when using get_posts($args) inside a function called via wp-ajax the way you call yours, and that solved it for me. Otherwise get_posts() wasn't able to retrieve any of the post information, hence the empty array you're seeing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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