8

I think I've got this 90% working, but it ends up 'uploading' a blank transparent image. I get a 201 response after the upload. I think that's probably a proxy for when WP finds a missing image. I'm unsure if i'm passing the image incorrectly (ie it doesn't leave my computer) or if I'm not tagging it properly to WP's liking.

from base64 import b64encode
import json
import requests

def imgUploadREST(imgPath):
    url = 'https://www.XXXXXXXXXX.com/wp-json/wp/v2/media'
    auth = b64encode('{}:{}'.format('USERNAME','PASS'))
    payload = {
        'type': 'image/jpeg',  # mimetype
        'title': 'title',
        "Content":"content",
        "excerpt":"Excerpt",
    }
    headers = {
        'post_content':'post_content',
        'Content':'content',
        'Content-Disposition' : 'attachment; filename=image_20170510.jpg',
        'Authorization': 'Basic {}'.format(auth),
    }
    with open(imgPath, "rb") as image_file:
        files = {'field_name': image_file}
        r = requests.post(url, files=files, headers=headers, data=payload) 
        print r
        response = json.loads(r.content)
        print response
    return response

I've seen a fair number of answers in php or node.js, but I'm having trouble understanding the syntax in python. Thank you for any help!

1
  • I've figured it out. Commented Jun 8, 2017 at 12:04

6 Answers 6

21

I've figured it out!

With this function I'm able to upload images via the WP REST api to my site (Photo Gear Hunter.) The function returns the ID of the image. You can then pass that id to a new post call and make it the featured image, or do whatever you wish with it.

def restImgUL(imgPath):
    url='http://xxxxxxxxxxxx.com/wp-json/wp/v2/media'
    data = open(imgPath, 'rb').read()
    fileName = os.path.basename(imgPath)
    res = requests.post(url='http://xxxxxxxxxxxxx.com/wp-json/wp/v2/media',
                        data=data,
                        headers={ 'Content-Type': 'image/jpg','Content-Disposition' : 'attachment; filename=%s'% fileName},
                        auth=('authname', 'authpass'))
    # pp = pprint.PrettyPrinter(indent=4) ## print it pretty. 
    # pp.pprint(res.json()) #this is nice when you need it
    newDict=res.json()
    newID= newDict.get('id')
    link = newDict.get('guid').get("rendered")
    print newID, link
    return (newID, link)
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for posting the solution. This is really nice. It worked for me also.
Is there an alternative configuration for using cookie-based authentication (WP's default)?
I'm afraid I don't know. My config was created long before I even thought about using a cookie.
2

To specify additional fields supported by the api such as alt text, description ect:

from requests_toolbelt.multipart.encoder import MultipartEncoder
import requests
import os
fileName = os.path.basename(imgPath)
multipart_data = MultipartEncoder(
    fields={
        # a file upload field
        'file': (fileName, open(imgPath, 'rb'), 'image/jpg'),
        # plain text fields
        'alt_text': 'alt test',
        'caption': 'caption test',
        'description': 'description test'
    }
)

response = requests.post('http://example/wp-json/wp/v2/media', data=multipart_data,
                         headers={'Content-Type': multipart_data.content_type},
                         auth=('user', 'pass'))

Comments

1

An improved version to handle non-ASCII in the filename (Greek, Cyrillic etc. letters for example). What it does is convert all non-ASCII characters to a UTF-8 escape sequence. (Original code from @my Year Of Code)

def uploadImage(filePath):
    data = open(filePath, 'rb').read()
    
    fileName = os.path.basename(filePath)
    
    espSequence = bytes(fileName, "utf-8").decode("unicode_escape")  
    # Convert all non ASCII characters to UTF-8 escape sequence

    res = requests.post(url='http://xxxxxxxxxxxxx.com/wp-json/wp/v2/media',
                        data=data,
                        headers={'Content-Type': 'image/jpeg',
                                 'Content-Disposition': 'attachment; filename=%s' % espSequence,
                                 },
                        auth=('authname', 'authpass'))
    newDict=res.json()
    newID= newDict.get('id')
    link = newDict.get('guid').get("rendered")
    print newID, link
    return (newID, link)

From my understading a POST HEADER can only contain ASCII characters

Comments

0

thanks to @my Year Of Code.

my final working code:

import 
HOST = "https://www.crifan.com"
API_MEDIA = HOST + "/wp-json/wp/v2/media"
JWT_TOKEN = "eyJxxxxxxxxjLYB4"

    imgMime = gImageSuffixToMime[imgSuffix] # 'image/png'
    imgeFilename = "%s.%s" % (processedGuid, imgSuffix) # 'f6956c30ef0b475fa2b99c2f49622e35.png'
    authValue = "Bearer %s" % JWT_TOKEN
    curHeaders = {
        "Authorization": authValue,
        "Content-Type": imgMime,
        'Content-Disposition': 'attachment; filename=%s' % imgeFilename,
    }
    # curHeaders={'Authorization': 'Bearer eyJ0xxxyyy.zzzB4', 'Content-Type': 'image/png', 'Content-Disposition': 'attachment; filename=f6956c30ef0b475fa2b99c2f49622e35.png'}
    uploadImgUrl = API_MEDIA
    resp = requests.post(
        uploadImgUrl,
        # proxies=cfgProxies,
        headers=curHeaders,
        data=imgBytes,
    )

return 201 means Created OK

response json look like:

{
  "id": 70393,
  "date": "2020-03-07T18:43:47",
  "date_gmt": "2020-03-07T10:43:47",
  "guid": {
    "rendered": "https://www.crifan.com/files/pic/uploads/2020/03/f6956c30ef0b475fa2b99c2f49622e35.png",
    "raw": "https://www.crifan.com/files/pic/uploads/2020/03/f6956c30ef0b475fa2b99c2f49622e35.png"
  },
...

more details refer my (Chinese) post: 【已解决】用Python通过WordPress的REST API上传图片

1 Comment

Since the header is a dictionary and not a string, the syntax can be written much simpler "Content-Disposition":"attachment; filename=" + espSequence
0

This is my working code for uploading image into WordPress from local image or from url. hope someone find it useful.

import requests, json, os, base64

def wp_upload_image(domain, user, app_pass, imgPath):
    # imgPath can be local image path or can be url
    url = 'https://'+ domain + '/wp-json/wp/v2/media'
    filename = imgPath.split('/')[-1] if len(imgPath.split('/')[-1])>1 else imgPath.split('\\')[-1]
    extension = imgPath[imgPath.rfind('.')+1 : len(imgPath)]
    if imgPath.find('http') == -1:
        try: data = open(imgPath, 'rb').read()
        except:
            print('image local path not exits')
            return None
    else:
        rs = requests.get(imgPath)
        if rs.status_code == 200:
            data = rs.content
        else:
            print('url get request failed')
            return None
    headers = { "Content-Disposition": f"attachment; filename={filename}" , "Content-Type": str("image/" + extension)}
    rs = requests.post(url, auth=(user, app_pass), headers=headers, data=data)
    print(rs)
    return (rs.json()['source_url'], rs.json()['id'])

Comments

-1
import base64
import os

import requests

def rest_image_upload(image_path):
    message = '<user_name>' + ":" + '<application password>'
    message_bytes = message.encode('ascii')
    base64_bytes = base64.b64encode(message_bytes)
    base64_message = base64_bytes.decode('ascii')

    # print(base64_message)

    data = open(image_path, 'rb').read()
    file_name = os.path.basename(image_path)
    res = requests.post(url='https://<example.com>/wp-json/wp/v2/media',
                    data=data,
                    headers={'Content-Type': 'image/jpg',
                             'Content-Disposition': 'attachment; filename=%s' % file_name,
                             'Authorization': 'Basic ' + base64_message})
    new_dict = res.json()
    new_id = new_dict.get('id')
    link = new_dict.get('guid').get("rendered")
    # print(new_id, link)
    return new_id, link

1 Comment

could be improved with explanations of your code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.