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.
The date format has to be in the format of RFC 3339:
ie: date(\DateTime::RFC3339, time());
ISO8601 gets rejected by the rest api.
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
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 🙂 )
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
Hi Corey,
Glad it helped. 🙂
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?
Hi Jerome!
It depends on server settings. If you see this line:
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.
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??
The image is uploaded to the media library.
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
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.
Ashuqur,
How is the image ID set, and how do we identify the image ID?
Thanks,
Steve
Hey Steve,
After the first request,
$uploaded_image->id
will have the image ID. If youvar_dump
the response from the first request, you can see all the information returned through the API.