Upload media via WordPress REST API

WordPress REST API is quite interesting especially when you are trying to update the website from some third-party resources. Recently I had to implement a similar feature where most of the things like custom post type, taxonomy etc. worked as they should except images. So, here I’m going to show how I made the media upload part work.

Although the media upload documentation says it should work with a single request, for some mysterious reason, it didn’t. I had to break the request into two parts.

Part 1: Upload the file

First I uploaded the image using a POST request. I only provided the image path in this request without any additional data.

//The image path in file system
$image_path = path/to/images/test-image.jpg;
//Upload the image
$uploaded_image = upload_image( $image_path );

I added CURL requests within the upload_image function.

function upload_image( $path ) {
    $request_url = 'http://websiteurl.com/wp/v2/media';

    $image = file_get_contents( $path );
    $mime_type = mime_content_type( $path );

    $api = curl_init();

    //set the url, POST data
    curl_setopt( $api, CURLOPT_URL, $request_url );
    curl_setopt( $api, CURLOPT_POST, 1 );
    curl_setopt( $api, CURLOPT_POSTFIELDS, $image );
    curl_setopt( $api, CURLOPT_HTTPHEADER, array( 'Content-Type: ' . $mime_type, 'Content-Disposition: attachment; filename="' . basename($path) . '"' ) );
    curl_setopt( $api, CURLOPT_RETURNTRANSFER, 1 );
    curl_setopt( $api, CURLOPT_HTTPAUTH, CURLAUTH_BASIC );
    curl_setopt( $api, CURLOPT_USERPWD, USERNAME . ':' . PASSWORD );

    //execute post
    $result = curl_exec( $api );

    //close connection
    curl_close( $api );

    return json_decode( $result );
}

The Content-Type and Content-Description values are very important while uploading image/media. Without appropriate mime type, the upload request will fail.

Part 2: Update media information

Once the image was successfully uploaded without any title, meta etc. I sent a second request to update the media.

/**
 * Let's update the image caption and other fields
 */
$fields = array(
    "date"          => date( 'Y-m-d H:i:s', $time ),
    "status"        => "publish",
    "title"         => "An interesting title for the image",
    "description"   => "Description of the image",
    "alt_text"      => "Images should have alt value",
    "caption"       => "Do not forget caption"
);
//Send the previously uploaded image ID in parameter
$updated_image = update_image_info( $uploaded_image->id, $fields );

The update_image_info function is pretty much the same as upload_image function.

function update_image_info( $id, $data = array() ) {
    $request_url = 'http://websiteurl.com/wp/v2/media/' . $id;

    $fields_string = json_encode( $data );

    $api = curl_init();

    //set the url, POST data
    curl_setopt( $api, CURLOPT_URL, $request_url );
    curl_setopt( $api, CURLOPT_POST, count($data) );
    curl_setopt( $api, CURLOPT_POSTFIELDS, $fields_string );
    curl_setopt( $api, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json' ) );
    curl_setopt( $api, CURLOPT_RETURNTRANSFER, 1 );
    curl_setopt( $api, CURLOPT_HTTPAUTH, CURLAUTH_BASIC );
    curl_setopt( $api, CURLOPT_USERPWD, USERNAME . ':' . PASSWORD );

    //execute post
    $result = curl_exec( $api );

    //close connection
    curl_close( $api );

    return json_decode( $result );
}

Notice that the Content-Type is different this time. That’s it. The $updated_image variable has the detail of newly uploaded media.

I’ve used basic authentication in the example for simplicity. But there are several other authentication methods available. Here is an interesting read about implementing OAuth2 with WP API.

 

Vultr VPS
name.com domains
Displate

Posted

in

, ,

by

Tags:

Comments

14 responses to “Upload media via WordPress REST API”

  1. Dirk Gustke Avatar

    The date format has to be in the format of RFC 3339:

    ie: date(\DateTime::RFC3339, time());

    ISO8601 gets rejected by the rest api.

    1. Ashiqur Rahman Avatar
      Ashiqur Rahman

      Hi Dirk,

      Thanks for pointing that out. If you use the full date-time format, this should be fine. More details here: https://core.trac.wordpress.org/ticket/41032

      1. Dirk Gustke Avatar

        I am pointing this out, since the exact line in your code example did not work for me, but using the line in my example did.

        For you to consider updating your example and for others to know how to make this work. (the stackoverflow way 🙂 )

  2. Corey Avatar

    Thank you, Ghumkumar, for this post. It’s helped me this week.

    I needed to insert media as attachments to a post, so I wrote a small plugin that allows viewing and editing the `post_parent` attribute of post types `post` and `attachment`. It lives here: https://github.com/mistercorey/wp-api-add-post-parent

    Also, I after inserting media, I wanted to set one of them as the featured image on the parent post. That means an API request to the parent post is required to set the `featured_image` attribute to the post ID of the attachment.

    Thanks again

    1. Ashiqur Rahman Avatar
      Ashiqur Rahman

      Hi Corey,
      Glad it helped. 🙂

  3. Jerome Dewald Avatar
    Jerome Dewald

    If the image is being retrieved from the internet, is it necessary to save it to a file before uploading it to WordPress?

    I iterate through a table of src’s and read an ADODB stream into a variable.
    Can’t I just send the variable in the request body?

    1. Ashiqur Rahman Avatar
      Ashiqur Rahman

      Hi Jerome!
      It depends on server settings. If you see this line:

      $image = file_get_contents( $path );
      

      We are reading the file content before sending the actual request. So if the server allows that from URL then this shouldn’t be a problem.

  4. mike last Avatar
    mike last

    Can I double check where you are initially uploading the image, is it to the wordpress media library or is it just to a tmp folder??

    1. Ashiqur Rahman Avatar
      Ashiqur Rahman

      The image is uploaded to the media library.

  5. John Ryan Avatar

    Hey Ash, I’m trying to use WooCommerce REST API to upload image files that include a dynamic reference (ie http://sitename/path-to-repository?ID=idname…… etc.)
    WC API reference (v3) states that the reference should be absolute, with a file extension.
    However, I have a valid link to the files using as above, but the request dies.
    I’m sure someone out there has a function that I can add to grab the dynamic url, change it to a proper reference, and move the file.
    I’m guessing that it would be a JS pre-request function, but I’m unsure how to implement this.
    Any ideas?
    Cheers
    JR

    1. Ashiqur Rahman Avatar

      Hey John,
      I’m not sure if you have found a solution already…

      Most websites use the dynamic file reference to prevent direct access/download from third-party or APIs. So, even if you can see the image in the browser when you place the dynamic URL, it might fail for API calls. Try and see if you can fetch the image using Postman. If you can, it should work for the API. If not, then as you said, you have to fetch the image and then upload it using the API.

  6. Steve Avatar
    Steve

    Ashuqur,
    How is the image ID set, and how do we identify the image ID?
    Thanks,
    Steve

    1. Ashiqur Rahman Avatar

      Hey Steve,
      After the first request, $uploaded_image->id will have the image ID. If you var_dump the response from the first request, you can see all the information returned through the API.

  7. sepon Avatar
    sepon

    I want to Upload image use wordpress REST api via Android. please help me

Leave a Reply

Your email address will not be published. Required fields are marked *