WP Rest API upload image - wordpress

I'm trying to upload image via Wordpress REST api v2. So far all I managed was to create empty entries in wordpress media library. Meaning they have image names, but no actual image.
POST Request:
http://localhost/wordpress/wp-json/wp/v2/media
Authorization: Basic d29yZHByZXNzOndvcmRwcmVzcw==
Content-Type: application/json
Content-Disposition: attachment;filename=map2.jpg
{
"source_url" : "file:///C:/Users/x/Desktop/map2.jpg"
}
Response:
{
"id": 127,
"date": "2016-05-25T08:43:30",
"date_gmt": "2016-05-25T08:43:30",
"guid": {
"rendered": "http://localhost/wordpress/wp-content/uploads/2016/05/map2-3.jpg",
"raw": "http://localhost/wordpress/wp-content/uploads/2016/05/map2-3.jpg"
},
"modified": "2016-05-25T08:43:30",
"modified_gmt": "2016-05-25T08:43:30",
"password": "",
"slug": "map2-3",
"status": "inherit",
"type": "attachment",
"link": "http://localhost/wordpress/map2-3/",
"title": {
"raw": "map2-3",
"rendered": "map2-3"
},
"author": 1,
"comment_status": "open",
"ping_status": "closed",
"alt_text": "",
"caption": "",
"description": "",
"media_type": "image",
"mime_type": "image/jpeg",
"media_details": {},
"post": null,
"source_url": "http://localhost/wordpress/wp-content/uploads/2016/05/map2-3.jpg",
"_links": {
"self": [
{
"href": "http://localhost/wordpress/wp-json/wp/v2/media/127"
}
],
"collection": [
{
"href": "http://localhost/wordpress/wp-json/wp/v2/media"
}
],
"about": [
{
"href": "http://localhost/wordpress/wp-json/wp/v2/types/attachment"
}
],
"author": [
{
"embeddable": true,
"href": "http://localhost/wordpress/wp-json/wp/v2/users/1"
}
],
"replies": [
{
"embeddable": true,
"href": "http://localhost/wordpress/wp-json/wp/v2/comments?post=127"
}
]
}
}
I get no errors, everything's seem to be working, except response->post and response->media_details is either null or empty. Ofcourse image itself is not uploaded.
Based on this GitHub WP-API Adding Media ticket, I should send 2 requests. First POST request should return data with post object. I would send this post object via PUT method, and image should be uploaded...since I have no post object, this is not possible.
Any ideas what am I doing wrong?

Sideloading images is not supported by the wordpress api so you will have to do some changes.
First, your content-type should be image/jpeg and not application/json, remember that content-type is supposed to reflect the data that you are passing and the POST media request expects an image.
Another change you have to make to accommodate the content-type is the way that you are passing the data. Instead of sending it with the source_url parameter, try passing it as a binary file.
One last thing I would mention is that the wp/v2 calls return 3XX status on a few occasions. It would be useful to follow those redirects and redo those requests to those new urls.
I had some issues passing JPEG images but PNG images have worked well. Here is a curl example that I use to upload png media:
curl --request POST \
--url http://www.yoursite.com/wp-json/wp/v2/media \
--header "cache-control: no-cache" \
--header "content-disposition: attachment; filename=tmp" \
--header "authorization: Basic d29yZHByZXNzOndvcmRwcmVzcw==" \
--header "content-type: image/png" \
--data-binary "#/home/web/tmp.png" \
--location

My working answer using PHP cUrl
<?php
$curl = curl_init();
$data = file_get_contents('C:\test.png');
curl_setopt_array($curl, array(
CURLOPT_URL => "http://woo.dev/wp-json/wp/v2/media",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => array(
"authorization: Basic XxxxxxxXxxxxXx=",
"cache-control: no-cache",
"content-disposition: attachment; filename=test.png",
"content-type: image/png",
),
CURLOPT_POSTFIELDS => $data,
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}

At january 2020 using wordpress 5.3.2 with nginx the solution that work for me is:
function uploadFile($token, $archivo) {
$file = file_get_contents( $archivo );
$mime = mime_content_type( $archivo );
$url = BASEAPI. 'wp-json/wp/v2/media';
$ch = curl_init();
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_POST, 1 );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt( $ch, CURLOPT_POSTFIELDS, $file );
curl_setopt($ch, CURLOPT_BINARYTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt( $ch, CURLOPT_HTTPHEADER, [
'Content-Type: '.$mime,
'Content-Disposition: attachment; filename="'.basename($archivo).'"',
'Authorization: Bearer ' .$token,
] );
$result = curl_exec( $ch );
curl_close( $ch );
print_r( json_decode( $result ) );
}
The token is the Authorization JWT token and $archivo is the path to file.

For anyone looking for a JS solution, here's how I made it work using Axios. I will skip authorization implementations, as there are a few options around (oAuth, JWT, Basic).
const fs = require('fs');
const axios = require('axios');
axios({
url: 'http(s)://{your-wp-domain}/wp-json/wp/v2/media',
method: 'POST',
headers: {
'Content-Disposition':'attachment; filename="file.jpg"',
Authorization: {your-authorization-method},
'Content-Type':'image/jpeg'
},
data: fs.readFileSync('path/to/file.jpg', (err, data) => {
if (err) {
console.log(err);
}
});
})
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});

Here you can use this code snippet. This works for me using Wordpress API REST
<?php
//Add this to your function.php
function upload_image( $imageID, $login ) {
$request_url = 'https://DOMAINNAME.com/wp-json/wp/v2/media'; //change the domainname
$image_file_path = get_attached_file($imageID); //change this to your file meda path if your not throwing media file to other server
$image = file_get_contents( $image_file_path );
$mime = mime_content_type( $image_file_path );
$api_media_response = wp_remote_post( $request_url, array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( $login ), //login format USERNAME:PASSWORD
'Content-Disposition' => 'attachment; filename='.basename($image_file_path).'',
'Content-Type' => $mime
),
'body' => $image
) );
//this function return wp_remote_post
// more info => https://developer.wordpress.org/reference/functions/wp_remote_post/
}

After trying to get the image upload running with wp_remote_post (donĀ“t wanna use curl for several reasons) i came up with the following working solution:
// Upload image to wordpress media library
$file = #fopen( 'image.jpg', 'r' );
$file_size = filesize( 'image.jpg' );
$file_data = fread( $file, $file_size );
$args = array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( 'USERNAME:PASSWORD' ),
'accept' => 'application/json', // The API returns JSON
'content-type' => 'application/binary', // Set content type to binary
'Content-Disposition' => 'attachment; filename=nameoffileonserver.jpg'
),
'body' => $file_data
);
$api_response = wp_remote_post( 'http://myserver.com/wp-json/wp/v2/media', $args);

if you want to upload a image to WordPress rest API using nuxtjs or vuejs you can use the below code:
in template:
<input style="display: none;" type="file" #change="onFileSelected"
<button #click="onUpload" />
in data:
data() {
return {
selectedFile: null,
previewImage: null
};}
in methods:
onFileSelected(event) {
this.selectedFile = event.target.files[0];
}
onUpload() {
const fd = new FormData();
fd.append("file", this.selectedFile, this.selectedFile.name);
fd.append("title", "pedram");
fd.append("caption", "this is caption");
/* file reader for prview image */
const reader = new FileReader();
reader.readAsDataURL(this.selectedFile);
reader.onload = e =>{
this.previewImage = e.target.result;
};
/* set request header */
const headers = {
'Content-Disposition':`attachment; filename=${this.selectedFile.name}`,
Authorization: "Bearer" + this.$cookiz.get("AdminToken"),
'content-type': 'image'
};
this.$axios.post('/wp-json/wp/v2/media', fd, { headers })
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
});
},
if you want to preview the image you can use file reader and store it in a data variable then use the data instead of image src like bellow code:
<img #click="$refs.fileInput.click()" v-if="previewImage" :src="previewImage" alt="" class="w-100" />
It took me one day to solve the issue I hope the above codes helps

Related

Posting with Symfony 4.4 HTTP Client not working, status code 422

I want to post info to external api but I get error 422 all the time. Geting info and authorization works fine. I'm using Symfony Http Client, authorization and headers are defined in framework.yaml for now.
Api documentation fragment:
curl "https://business.untappd.com/api/v1/locations/3/custom_menus"
-X POST
-H "Authorization: Basic bmlja0BuZXh0Z2xhc3MuY286OW5kTWZESEJGcWJKeTJXdDlCeC0="
-H "Content-Type: application/json"
-d '{ "custom_menu": { "name": "Wine selection" } }'
My service fragment:
public function customMenu(): int
{
$response = $this->client->request(
'POST',
'https://business.untappd.com/api/v1/locations/'.$this->getLocationId().'/custom_menus',
[
'json' => [
['custom_menu' => ['name' => 'Wine selection']],
],
]
);
Try to encode json "manualy", before send. Just like that
//$jsonData = '{ "custom_menu": { "name": "Wine selection" } }';
$jsonData = json_encode(["custom_menu" => ["name" => "Wine selection"]]);
$response = $client->request(
'POST',
'https://business.untappd.com/api/v1/locations/'.$this->getLocationId().'/custom_menus',
[
'headers' => [
'Content-Type' => 'application/json',
],
'body' => $jsonData,
]
);
There are an error and some missing parameters you didn't include:
The most important : Authorization (if you didn't add it to your framework.yaml file under 'http_client' parameter).
Your link ends with 'custom_menus' not 'menus'.
The content-type.
You can test this correction:
public function customMenu(): int
{
$response = $this->client->request(
'POST',
'https://business.untappd.com/api/v1/locations/'.$this->getLocationId().'/custom_menus', //corrected '/custom_menus'
[
'auth_basic' => ['bmlja0BuZXh0Z2xhc3MuY286OW5kTWZESEJGcWJKeTJXdDlCeC0='], // To add
'headers' => [ // To add
'Content-Type' => 'application/json',
],
'json' => [
['custom_menu' => ['name' => 'Wine selection']],
],
]
);
// .....
}

Wordpress intercepting response Location header impossible, response headers are always null and empty

I am developing a plugin for a wordpress website which interacts with a third party HTTP API.
For one specific request I am completely dependent on a response header. It's a Location header used for redirection, from which I need to get the url and query parameters.
The request:
return wp_remote_post($url, array(
'body' => http_build_query(array(
'token' => <omitted>,
'email' => <omitted>,
'password' => <omitted>
)),
'headers' => array(
'Content-Type' => 'application/x-www-form-urlencoded'
),
'redirection' => 0
));
While testing the request above I noticed the headers response fields are null and {}:
{
"headers": {},
"body": "",
"response": {
"code": 303,
"message": "See Other"
},
"cookies": [
{
"name": "JSESSIONID",
"value": "<omitted>",
"expires": null,
"path": "/<omitted>",
"domain": "test.<omitted>.com",
"host_only": true
}
],
"filename": null,
"http_response": {
"data": null,
"headers": null,
"status": null
}
}
The request is working fine in Postman, where all the expected response headers are clearly visible. I also turned off following redirections in Postman for this specific request to be able to intercept the Location header before the redirection occurs.
I have tried:
another wordpress instance: same issue, no headers
a local docker wordpress instance: same issue, no headers
a different http request (GET https://example.com): same issue, no headers
setting redirection to 1 instead of 0: same issue, no headers, BUT the redirect actually works, which means the Location header is present and wp_remote_post picked it up - this makes it even harder to understand why I cannot see or retrieve any headers.
Here's the response when I GET https://example.com:
{
"headers": {},
"body": "<omitted>",
"response": {
"code": 200,
"message": "OK"
},
"cookies":[],
"filename": null,
"http_response": {
"data": null,
"headers": null,
"status": null
}
}
I have been searching for hours and I haven't gotten a step closer to resolving this issue. Any assistance is most welcome.
edit: someone asked me for the cURL PHP code from Postman:
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => '<omitted>/auth/login',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => 'token=<omitted>&email=<omitted>&password=<omitted>',
CURLOPT_HTTPHEADER => array(
'Content-Type: application/x-www-form-urlencoded',
'Cookie: JSESSIONID=<omitted>'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
I worked around this issue by using another http library 'Requests'.
Wordpress usually includes this library by default.
$url = "$this->base_url/$this->base_path/auth/login";
$headers = array('Content-Type' => 'application/x-www-form-urlencoded');
$data = array(
'token' => <omitted>,
'email' => <omitted>,
'password' => <omitted>
);
$options = array(
'follow_redirects' => false
);
return Requests::post($url, $headers, $data, $options);
It does not solve the issue with wp_remote, but replaces it nicely for this specific request.

Wordpress + Vimeo API | Find Specific Video Via URI

So I am trying to utilize the Vimeo API in Wordpress to automatically embed a specific video, but the information I will have available is the URI. I created the following call in Postman which retrieves what I need, but I am struggling with how to authenticate via token to get this in Wordpress. I have a custom field in the post type that is "Vimeo URI" and want to use that in the call. Here is what I have in Postman:
GET https://api.vimeo.com/videos?fields=uri,name,link&uris={VIDEOURI}
That returns (data replaced):
{
"total": 1,
"page": 1,
"per_page": 25,
"paging": {
"next": null,
"previous": null,
"first": "/videos?fields=uri%2Cname%2Clink&uris=%2Fvideos%2F441653190&page=1",
"last": "/videos?fields=uri%2Cname%2Clink&uris=%2Fvideos%2F441653190&page=1"
},
"data": [
{
"uri": "VIDEO URI",
"name": "VIDEO NAME",
"link": "VIDEO URL"
}
]
}
Here is how I started the request in functions.php:
$uri = the_field( 'vimeo_uri' );
$args_for_get = array(
'headers' => array(
'Authorization' => 'bearer INSERTED MY TOKEN HERE'
),
'fields' => 'uri,name,link',
'uri' => $uri
);
$url = 'https://api.vimeo.com/videos';
$request = wp_remote_get( $url, $args_for_get );
return load_request($request);
function load_request($response) {
try {
$json = json_decode( $response['body'] );
} catch ( Exception $ex ) {
$json = null;
}
return $json;
}
$json->data->link = $vimeolink;
This comes back with 400 bad request from Vimeo. Would appreciate any help on getting this to work. Also, should I be architecting this differently? The idea is for this call to go out on page load for each post that has the URI field, but maybe I should be scraping the data to a plugin instead and then retrieving the data from there?

Upload pano Image using street View Publish API

When I am making upload using the the given street View API
Request an Upload URL
$ curl --request POST \
--url 'https://streetviewpublish.googleapis.com/v1/photo:startUpload?key=YOUR_API_KEY' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
--header 'Content-Length: 0'
Upload the photo bytes to the Upload URL
$ curl --request POST \
--url 'UPLOAD_URL' \
--upload-file 'PATH_TO_FILE' \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
But its not Working..
Its giving me the error No file found in request.
Can anybody please help me regarding this ..
Thank you in Advance.
To Get the upload URL I solved By this way
$cur_upload_url = curl_init();
curl_setopt_array($cur_upload_url, array(
CURLOPT_URL => "https://streetviewpublish.googleapis.com/v1/photo:startUpload?key=XXXXXXXXXXX" ,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "" ,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => array(
"authorization: Bearer $access_token",
"content-type: application/json",
"Content-Length: 0"
),
));
$response = curl_exec($cur_upload_url);
$re = '/https?:\/\/[^"]*/';
$str = $response;
preg_match($re, $str, $matches, PREG_OFFSET_CAPTURE, 0);
$upload_url = $_SESSION['UploadRef'] = $matches[0][0];
echo $upload_url;
Upload the photo bytes to the Upload URL
$cmd = exec('curl --request POST \--url "'. addslashes($upload_url) .'" \--upload-file "'.$imagePath.'" \--header "Authorization: Bearer '. addslashes($access_token) .'" ');
Then Uplaod the meta data of photo
$curl_meta = curl_init();
curl_setopt_array($curl_meta, array(
CURLOPT_URL => "https://streetviewpublish.googleapis.com/v1/photo?key=XXXXXXXXXXXXXXXX",
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => '{
"uploadReference":
{
"uploadUrl": "'.$upload_url.'"
},
"pose":
{
"heading": 95.0,
"latLngPair":
{
"latitude": '.$latVal.',
"longitude": '.$langVal.'
}
},
"captureTime":
{
"seconds": '.$time_stamp.'
},
}',
CURLOPT_HTTPHEADER => array(
"authorization: Bearer $access_token",
"content-type: application/json"
),
));
$response_meta = curl_exec($curl_meta);
$response_json = json_decode($response_meta, true);
// $photoID = $response_json['photoId']['id'];
// echo $photoID;
if(curl_errno($curl_meta)){
// this would be your first hint that something went wrong
die('Couldn\'t send request: ' . curl_error($curl_meta));
}else{
//check the HTTP status code of the request.
$resultStatus = curl_getinfo($curl_meta, CURLINFO_HTTP_CODE);
if($resultStatus != 200){
die('Request failed: HTTP status code: ' . $resultStatus);
}else{
$photoID = $response_json['photoId']['id'];
//insert google publish information into db table
}
}
curl_close($curl_meta);
From here you will get the photo ID.
After getting the Photo iD publish is successful.
If anyone looking some option to upload via node.js server:
import { exec } from 'child_process';
await new Promise((resolve, reject) => {
const uploadCmd = `curl --request POST \ --url "${uploadUrl}" \ --upload-file "${__dirname}/360.jpg" \ --header "Authorization: Bearer ${accessToken}" `;
exec(uploadCmd, (err, stdout, stderr) => {
if (err) {
// node couldn't execute the command
console.log('err', err);
reject(err);
return false;
}
resolve({stdout, stderr});
console.log(`Succesfully uploaded:
stdout: ${stdout}
stderr: ${stderr}
`);
});
});
Don't forget to do the await part in an async function.

Always get {"error":"Unsupported Media Type"} from Watson-Conversation service

The following code is very straightforward. However, when I execute it, I always get {"error":"Unsupported Media Type"} from Watson-Conversation service. Please help to show me where the issue comes from.
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_POST => true,
CURLOPT_URL => "https://watson-api-explorer.mybluemix.net/conversation/api/v1/workspaces/70b056e6-14a0-424f-9631-696272ce666e/message?version=2016-09-20",
CURLOPT_USERPWD => "{MYUSERNAME}:{MYPASSWORD}",
CURLOPT_POSTFIELDS => array('message' => '{ "input": { "text": "Hola" }, "alternate_intents": false }'),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => true
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err)
{
echo "cURL Error #:" . $err;
}
else
{
echo $response;
}
Thank you very much.
I have sorted it out already by adding following option into the call:
CURLOPT_HTTPHEADER => array('Content-Type: application/json')

Resources