How to post content to WordPress using Python and Rest API

wordpress

#1

To get familiar with WordPress REST API, I fired up Python started playing with the requests module, the elegant and simple HTTP library for Python, built for human beings. Python and the WordPress REST API Handbook gave me enough information to get started.

The default cookies authentication mechanism would not work with Python and you need to install a plugin for this sort of application. See this tutorial on how to use the WordPress OAuth 1.0a plugin.

For a quick demo, the Application Passwords plugin for WordPress is the easiest choice. The installation is straightforward, and the instructions to generate a password for the client application are quite simple to follow. I needed to modify the .htaccess file due to the way my DreamPress site is configured. Notice: the password generated by the plugin contains white spaces, and they are part of the password. Once the WordPress authentication is taken care of, it’s all much easier.

On to Python, get json and requests modules ready, set the base URL of your WordPress site, your username and the application password generated by the plugin (including the white spaces):

import requests
import json

user = 'username'
pythonapp = 'G4kN hBNh r35J luXk aXyd n6Lm'
url = 'https://example.com/wp-json/wp/v2'

The Application Password plugin requires a token made of username and password encoded in base64, so let python create it and add that to the http headers:

token = base64.standard_b64encode(user + ':' + pythonapp)
headers = {'Authorization': 'Basic ' + token}

Next, prepare some demo content for a new post. WordPress API expect a JSON object:

post = {'date': '2017-06-19T20:00:35',
        'title': 'First REST API post',
        'slug': 'rest-api-1',
        'status': 'publish',
        'content': 'this is the content post',
        'author': '1',
        'excerpt': 'Exceptional post!',
        'format': 'standard'
        }

That’s all you need to create a post:

r = requests.post(url + '/posts', headers=headers, json=post)
print('Your post is published on ' + json.loads(r.content)['link'])

You’ll see printed on screen the URL of the new post. That was fun and quick :slight_smile: Now let’s publish an image: first you have to add it to the Media library (as you would when you use WordPress admin panel). To publish images you’ll need to use the media API endpoint. For the example, use the file demo.jpg in the current directory

media = {'file': open('demo.jpg',rb),
'caption': 'My great demo picture'}

And let Python requests do the heavy lifting:

image = requests.post(url + '/media', headers=headers, files=media)
print('Your image is published on ' + json.loads(image.content)['link'])

That should give you the URL for the image you just uploaded. Now to embed that image in a post, we can edit its content. To update a post we need to find its ID and push to the API endpoint the new value using JSON.

imgsrc = json.loads(up.content)['source_url']
postid = json.loads(r.content)['id']
updatedpost = {'content': 'Changed things.<img src=' 
        + imgsrc
        + '>'}

Update the post with the new content:

update = requests.post(url + '/posts/' + postid, headers=headers, json=updatedpost)
print('The updated post is published on ' + json.loads(updatedpost.content)['link'])

And that’s all: you created a new post, added an image to WordPress media library and modified a post using only Python and the REST API.


#2

@smaffulli Hello,
I have a doubt tho…
What if I want to upload a media from URL?
Like for example “http://pngimg.com/uploads/xbox/xbox_PNG17529.png
So… Instead of

 media = {'file': open('demo.jpg',rb)}

can i do…

media = {'file': <img src=\"http://pngimg.com/uploads/xbox/xbox_PNG17529.png\" />"}

or

media = {'file': urllib.request.urlopen("http://pngimg.com/uploads/xbox/xbox_PNG17529.png")}

And then use this media… as the Featured Image Only?
I am not sure whether this will work… Thank you for every and any kind of Help :blush:


#3

I think that as long as the media contains an image for Python, it should work. Try and see if/how that fails.


#4

@smaffulli Ok… I will try that out and … How do I use that same image in the same program to set as Featured Image?
Thank you :slight_smile:


#5

Hi. I am trying to make this work but I get this error:

Traceback (most recent call last):
  File "filename", line 10, in <module>
    token = base64.standard_b64encode(user + ':' + pythonapp)
  File "filename", line 98, in standard_b64encode
    return b64encode(s)
  File "filename", line 62, in b64encode
    encoded = binascii.b2a_base64(s)[:-1]
TypeError: a bytes-like object is required, not 'str'

Any ideas on how to fix it? I’m a beginner and I’m using Python 3.5 and PyCharm. Both Application Password and WordPress REST API plugins installed successfully.

As for the URL, is it OK if I use just “https://anydomainname.com”? Or should I specify any directories?

Thank you!


#6

@sdk If you use python3.5 or later then you have to encode slightly differently.

token = base64.standard_b64encode(b’user + “:” + pythonapp’)
headers = {‘Authorization’: 'Basic ’ + str(token)}

I changed these lines to this and it now works.


#7

It uses the built in REST module, so you can just POST new content to your website. I’d take a look at the jQuery example, probably the closest to python it gets. You will need to authenticate and get the CSRF token from the REST module.


Mini Militia App Lock . 7Zip


#8

Thanks for sharing @smaffulli.

I tried this with Python 3.5 and had to make some changes to your code. I thought I’d share my final working code for creating a new post – in case other folks using Python 3.5+ find it helpful:

import requests
import json
import base64

user = 'username'
pythonapp = 'G4kN hBNh r35J luXk aXyd n6Lm'
url = 'https://example.com/wp-json/wp/v2'

data_string = user + ':' + pythonapp

token = base64.b64encode(data_string.encode())

headers = {'Authorization': 'Basic ' + token.decode('utf-8')}

post = {'date': '2017-06-19T20:00:35',
		'title': 'First REST API post',
		'slug': 'rest-api-1',
		'status': 'publish',
		'content': 'this is the content post',
		'author': '1',
		'excerpt': 'Exceptional post!',
		'format': 'standard'
		}

r = requests.post(url + '/posts', headers=headers, json=post)

print('Your post is published on ' + json.loads(r.content.decode('utf-8'))['link']) 

–Omer


#9

iam getting the error while using this code…solution pls