WP Rest API upload image

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:

Read More
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?

Related posts

Leave a Reply

7 comments

  1. 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
    
  2. 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;
    }
    
  3. 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);
     });
    
  4. 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.

  5. 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/
    }
    
  6. 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);
    
  7. 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