7

I want to check if a post already exists. This includes to check if the post exists as draft as well. But I struggle a little bit with the wordpress API v2. http://v2.wp-api.org/reference/posts/
Under List Posts -> status they say

Limit result set to posts assigned a specific status.
Default: publish

I tried to assign the value as parameter, but I get an error response:

{"code":"rest_invalid_param","message":"Invalid parameter: status","data":{"status":400,"params":{"status":"Status is forbidden"}}}

I als asign the title of the post to check:

filter[s] = post Title

So how to get the posts with draft state? I'm currently using the Basic Auth for developing?

I also tried

filter[post_status]=draft

but with no success.

I have the following plugins installed: WP REST API
WP REST API - filter fields
JSON Basic Authentication

4 Answers 4

4

I think the query parameter that you want for post status is:

status=draft

Let me know if this doesn't work.

4
  • Yes that worked, thanks. I tried it with this at the beginning but it didn't work, so I'm confused that it works now.
    – Ronon
    Dec 1, 2016 at 20:19
  • 3
    Hi! For some reason it does not seem to work for me. WP 5.3.2 and I get that status is forbidden. Using the following url: localhost/wordpress/wp-json/wp/v2/posts?status=draft The exact JSON I get is this: {"code":"rest_invalid_param","message":"Invalid parameter(s): status","data":{"status":400,"params":{"status":"Status is forbidden."}}} Feb 11, 2020 at 3:13
  • 1
    @AndreaRaimondi that is, because status draft is protected and not queriable via rest simply by adding the attribute to the url. cause that would allow to query all wordpress apis to expose drafts simply by adding the attribute. you are still able to change that behavior, though..
    – honk31
    Jun 1, 2021 at 16:11
  • @honk31 , What do you do in that case? I have sent a new JWT token in the header with the query string in the above comment. I get the same error. I have tried to append username and application password as http variables, nada. I can't send them as post variables because it is a GET request, not a POST request. Any help would be appreciated.
    – TARKUS
    Jun 8, 2021 at 18:28
1

that is due to the fact, that draft is a protected status. and protected status are not publicly queriable simply by adding the attribute to the url. because that would mean, that everybody could query any wordpress api and query for "hidden" posts. by default protected statuses are ‘future‘, ‘draft‘ and ‘pending‘.

but you still could change that behavior for your api...

following is a working example, but it only exposes drafts to logged in users:

/**
* make drafts public for logged in users
*/
function so240254_init()
{
    if (is_user_logged_in()) :
        global $wp_post_statuses;

        $wp_post_statuses['draft']->public = true;
        $wp_post_statuses['draft']->exclude_from_search = false;
        $wp_post_statuses['draft']->publicly_queryable = true;
    endif;
}
add_action('init', 'so240254_init');

/*
* expose drafts to api for logged in users
*/
function so240254_rest_post_query($args)
{
    if (is_user_logged_in()) :
        $args['post_status'] = ['publish', 'draft'];
    endif;

    return $args;
}
add_filter('rest_post_query', 'so240254_rest_post_query');

now, when you are logged in and call the rest api, you get published and draft posts (no query parameter required!). if not, you only get published posts.

you could strip the is_user_logged_in() method, if you really wanted to expose drafts to all queries, no matter the current user status...

5
  • I thought if you pass the JWT authentication token you should be able to get the status=draft ? I'm using basic/wp-json/wp/v2/posts?status=draft and getting the same error. I successfully get a valid JWT token, which I pass in the header. Seems like the point of using a token is so that things like this work. I would add that is_user_logged_in() = 1, so I'm logged in, but I still get [code] => rest_invalid_param [message] => Invalid parameter(s): status
    – TARKUS
    Jun 8, 2021 at 13:47
  • @TARKUS what do you mean with is_user_logged_in() = 1?? is_user_logged_in() is a function, that returns true or false, = 1 doesn't make any sense in my eyes? never used the JWT plugin, so not sure, if it helps on this end. but i can confirm, that status=publish works fine, while status=draft throws the invalid parameter(s): status error.
    – honk31
    Jun 9, 2021 at 15:31
  • I'm pretty sure "1" is synonymous with TRUE. And my problems with status=draft was my own damn fault, I had an errant single quote in the header I was passing with Authorization: Bearer <token>. Once I looked at it and fixed it, now everything works. I also recommend JWT Authentication because you pass an "application password" to get the token, instead of the user's WP password. Anyway, thanks.
    – TARKUS
    Jun 9, 2021 at 15:55
  • yes, you are absolutly correct, 1 casts as TRUE, but =? simply put: single equal sign SETS a value, double equal sign COMPARES values and tripple equal sign also compares, but more strict. glad it works now..
    – honk31
    Jun 10, 2021 at 10:24
  • Ah, well that was my shorthand for a logical operator, not the actual code. I probably just output something like echo "logged in = " . is_user_logged_in(); which would have output to the screen as "logged in = 1".
    – TARKUS
    Jun 10, 2021 at 13:26
1

Having recently been through a similar problem, and learning to solve it, I thought I'd share my learning experience.

As we learned, anybody can request a post with status=publish. If you get errors like the following or similar, then you should start thinking in terms of problems with authentication or permissions:

stdClass Object
(
    [code] => rest_invalid_param
    [message] => Invalid parameter(s): status
    [data] => stdClass Object
        (
            [status] => 400
            [params] => stdClass Object
                (
                    [status] => Status is forbidden.
                )

            [details] => stdClass Object
                (
                    [status] => stdClass Object
                        (
                            [code] => rest_forbidden_status
                            [message] => Status is forbidden.
                            [data] => stdClass Object
                                (
                                    [status] => 401
                                )

                        )

                )

        )

    )

...or...

stdClass Object
(
    [code] => jwt_auth_invalid_token
    [message] => Wrong number of segments
    [data] => stdClass Object
        (
            [status] => 403
        )

)

...If you are logged in as an admin, then you should have permission to see draft posts. Therefore, it is likely your API calls are not authenticating for some reason.

The first thing I tested was the token. I happen to be using the JWT Authentication for WP-API plugin, which is actually pretty easy to implement. After installing/activating JWT Auth, go to the user you want to assign to use your API calls, and at the bottom of the user profile you will see :

Application Account name

Give your application a name, Add New, and then a new application password will pop up. It will look like this:

Application password

Copy the whole password, keeping the spaces is fine.

I'm using PHP and cURL, so my get token code looks like this:

private function getAuthHeader(){
    $JWTtoken = json_decode($this->getJWTToken());
    $token = $JWTtoken->token;
    $header = array(
        "Content-type: application/json", 
        "Authorization: Bearer " . $token
    );
    return $header;
}

public function getJWTToken(){
    /*
    Request: POST http://basic/wp-json/api/v1/token
    Body:
    username = <wordpress username>
    password = <wordpress password>
    */
    
    $url = $this->baseurl . "jwt-auth/v1/token";

    $params = array(
                        'requesttype' => 'POST',
                        'url' => $url,
                        'post' => array('username' => 'admin', 'password' => 'esmA UJom vxAG LFKU q8oN DSGK')
                    );
    $ch = curl_init();
    CURL_SETOPT($ch, CURLOPT_RETURNTRANSFER, 1);
    CURL_SETOPT($ch, CURLOPT_URL, $params['url']);
    CURL_SETOPT($ch, CURLOPT_POST, TRUE);
    CURL_SETOPT($ch, CURLOPT_POSTFIELDS, http_build_query($params['post']));
    CURL_SETOPT($ch, CURLOPT_SSL_VERIFYPEER, false);
    $response = curl_exec($ch);
    curl_close($ch);
    return $response;
}

...You will see way down in $params where I set the username/password. The username is "admin", because that's the user I set the new application password for, and the password is esmA UJom vxAG LFKU q8oN DSGK. Notice I'm NOT using the admin's WordPress password.

Your header becomes an array, and it should look something like this, which includes a loooong token string:

Array ( [0] => Content-type: application/json [1] => Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9iYXNpYyIsImlhdCI6MTYyMzI2NjUyNSwibmJmIjoxNjIzMjY2NTI1LCJleHAiOjE2MjM4NzEzMjUsImRhdGEiOnsidXNlciI6eyJpZCI6IjEifX19.YX1UvJ5nlbG2MIlheI2NzTTzaQKBZ8I9WQOr70CE1Tk ) 

Finally, the function that makes the request using cURL looks like this:

public function getResponse($params){

    $auth_header = $this->getAuthHeader();

    $ch = curl_init();
    CURL_SETOPT($ch, CURLOPT_RETURNTRANSFER, 1);
    CURL_SETOPT($ch, CURLOPT_URL, $params['url']);
    if( isset($params['requesttype']) && $params['requesttype'] == "POST" ){ //additional code to detect whether I'm making a GET, POST, or PUT request.
        CURL_SETOPT($ch, CURLOPT_POST, TRUE);
    }
    else if( isset($params['requesttype']) && $params['requesttype'] == "PUT"){
        CURL_SETOPT($ch, CURLOPT_CUSTOMREQUEST, "PUT");
    }
    if(isset($params['post'])){
        CURL_SETOPT($ch, CURLOPT_POSTFIELDS, http_build_query($params['post']));
    }
    CURL_SETOPT($ch, CURLOPT_SSL_VERIFYPEER, false);
    CURL_SETOPT($ch, CURLOPT_HTTPHEADER, $auth_header);
    $response = curl_exec($ch);
    curl_close($ch);
    return $response;
}

Notice that before executing the cURL, I want to get my header, with the new token, by calling the getAuthHeader function:

$auth_header = $this->getAuthHeader();

and notice that I have to pass that header, which contains the new token, to the web service:

CURL_SETOPT($ch, CURLOPT_HTTPHEADER, $auth_header);

Barring any typos, which is always my problem, this should return posts with status=draft:

    public function getPosts($params){
        // I passed $params['status'] = "draft";
        $url = $this->baseurl . "wp/v2/posts/?status=" . $params['status'] . "";
        $data = array(
                        'requesttype' => 'GET',
                        'url' => $url
                     );
        return $this->getResponse($data);
    }
1

this is work for me as well

add_action('init', function ()
{
    if (is_user_logged_in()) :
        global $wp_post_statuses;

        $wp_post_statuses['draft']->public = true;
        $wp_post_statuses['draft']->exclude_from_search = false;
        $wp_post_statuses['draft']->publicly_queryable = true;
    endif;
});

add_filter('rest_post_query', function ($args)
{
        $args['post_status'] = ['publish', 'draft'];
    return $args;
});

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.