Note that the constructor of `WP_Query` [is][1]: public function __construct( $query = '' ) { if ( ! empty( $query ) ) { $this->query( $query ); } } so you need a non-empty query input in your current code snippet. Here's a simple test example: $query = new WP_Query( ['post_type' => 'post' ] ); wp_send_json_success( $query->posts ); but you can check out e.g. [`wp_ajax_query_attachments()`][2] to see how WordPress uses `WP_Query` in an ajax call. [1]: https://github.com/WordPress/WordPress/blob/f1be128cde8f743a3c7563ceacf496a01e1cbce8/wp-includes/class-wp-query.php#L3355 [2]: https://developer.wordpress.org/reference/functions/wp_ajax_query_attachments/