When I load posts in the frontend via AJAX, I also see posts that have the status "Draft":

function get_projects() {
    $args = array("post_type" => "project");
    $loop = new \WP_Query($args);

    $projects = array();

    while($loop->have_posts()) {

        $project = '...';
        array_push(projects, $project);

    echo json_encode($projects);


add_action('wp_ajax_get_projects', 'get_projects');
add_action('wp_ajax_nopriv_get_projects', 'get_projects');

The WordPress doc says the following about this:

post_status (string / array) – use post status. Retrieves posts by post status. Default value is ‘publish‘, but if the user is logged in, ‘private‘ is added. Public custom post statuses are also included by default. And if the query is run in an admin context (administration area or AJAX call), protected statuses are added too. By default protected statuses are ‘future‘, ‘draft‘ and ‘pending‘.

Source (WordPress Developer Resources)

Is there any way to prevent the status "protected" from being issued as well?

  • if you only want published posts, have you tried explicitly asking WP_Query for only posts with the published status?
    – Tom J Nowell
    Jan 31, 2023 at 14:15

1 Answer 1


admin-ajax.php is treated as part of the admin, so protected statuses will be included. To solve this just explicitly define post_status as publish to only get published posts:

$args = array( 'post_type' => 'project', 'post_status' => 'publish' );

Or, better yet, consider using the REST API for AJAX requests, instead of the aging admin-ajax.php approach. If you want to query a custom type and receive JSON then you probably don't even need to create your own endpoint.

Your Answer

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

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