Being a lazy person I prefer to automate as much as possible instead of performing routine work manually. Well, you need to make it once to know what you need to automate, but that is where it stops for me.
So I had a goal of preparing and publishing a number of posts on my (only in Russian for now, sorry) website for motorcycle enthusiasts, where the data could nicely fit into a database and when available it can be wrapped in a template and posted. OK, I need to get the data myself, but publishing tenth of posts is NOT an option. Luckily I had already Jetpack installed, which gave me access to the JSON API.
I will describe separately how to obtain the proper authorization tokens (not sure I can repeat it, it is made for confusion, not sure about security though). When you do have those you can use API. My favorite language of choice for automation is Python, therefore I started typing code before even thinking of selecting a different language.
A simple request is a no-brainer:
import urllib2 import json import sys ACCESS_KEY = 'YOUR ACCESS KEY' WEBSITE = 'YOUR WEBSITE NUMBER' url = 'https://public-api.wordpress.com/rest/v1.1/sites/%s/posts/' % WEBSITE_NUMBER headers = { 'Authorization' : 'Bearer ' + ACCESS_KEY }; id = sys.argv[1] # OK a HACK, I admit. req = urllib2.Request(url + id, headers=headers) response = urllib2.urlopen(req) response_data = response.read() post_json = json.loads(response_data) print post_json
So this is actually a useful script to get information on your post (provide number in command line) in JSON format. Note that the content will be there as well, so it may be a lot :).
Fun starts when you start publishing things.
First, try to publish a media file. Since I prefer to work with standard library for max and easy portability (I switch between different computers on daily basis) I wanted to stick to urllib(2)-like things. This proved to be more difficult, but thanks to this post that was not that difficult.
What did cost me quoite some sleepless night time is that you should not forget that web requests and unicode (difficult subject in Python 2 anyway) do NOT live together. In other words
form = MultiPartForm() form.add_field('media[]', str(file_name)) # ENSURE TO PROVIDE STR, NOT UNICODE! form.add_field('attrs[0][title]', str(title))
In my case both file_name and title happened to be in unicode. Tadaaa… Here we go with dreaded UnicodeDecodeError’s. Took me ages to find this one out.
Second, the less obvious for me was the format of the post request when I needed to add/update metadata for a post. There is what documentation says:
Array of metadata objects containing the following properties: `key` (metadata key), `id` (meta ID), `previous_value` (if set, the action will only occur for the provided previous value), `value` (the new value to set the meta to), `operation` (the operation to perform: `update` or `add`; defaults to `update`). All unprotected meta keys are available by default for read requests. Both unprotected and protected meta keys are avaiable for authenticated requests with proper capabilities. Protected meta keys can be made available with the rest_api_allowed_public_metadata filter.
So now you just have to specify “array of metadata objects” and off you go… If you know what do they mean by this. I spent hours debugging WordPress and Jetpack code with ‘poor man’ tools like log_error
statements. Never mind.
Here is how you can add new meta-data.
HEADERS = { 'Authorization' : 'Bearer ' + ACCESS_KEY } POSTS_API = 'https://public-api.wordpress.com/rest/v1.1/sites/%s/posts/' % 'YOUR WEBSITE ID' post_url = POST_API + 'YOUR POST ID' post_values = { 'featured_image' : featured_image_id, 'metadata[0][key]' : 'test-key', 'metadata[0][value]' : 'test-value', 'metadata[0][operation]' : 'add' } request_data = urllib.urlencode(post_values) request = urllib2.Request(post_url, request_data, headers=HEADERS) response = urllib2.urlopen(request) response_raw = response.read() post_json = json.loads(response_raw) # Here you can inspect post_json for all responses.
To update existing values you have to find the ID of the corresponding metadata first:
# Find metadata from previously requested data on your post. See examples above. metadata_id = None for m in post_json['metadata']: if m and (u'key' in m) and (m[u'key'] == u'test-key'): metadata_id = m[u'id'] post_values = { 'metadata[0][id]' : metadata_id, 'metadata[0][key]' : 'test-key', 'metadata[0][value]' : 'test-value', 'metadata[0][operation]' : 'update' } request_data = urllib.urlencode(post_values) request = urllib2.Request(post_url, request_data, headers=HEADERS) response = urllib2.urlopen(request) response_raw = response.read() post_json = json.loads(response_raw)
I hope this saves time for somebody.