Diving into the REST:
Once I had WordPress running on Docker,
it was time to investigate the WordPress REST API. This API, available in WordPress core since release 4.7, is accessible right out of the box. To test it's presence:
http://localhost:8000/?rest_route=/
However trying to get read access to the sample posts:
http://localhost:8000/wp-json/wp/v2/posts
Fails with 404 not found.
To fix this enable pretty links, which allows a better way to access the api
- login as admin at http://localhost:8000/wp-login.php
- Go to Settings ==> Permalinks
- Choose 'Post Name' in the Common Settings, then Save Changes
And test via the browser:
localhost:8000/wp-json/wp/v2/posts ...show the hello world post
localhost:8000/wp-json/wp/v2/categories ...list the 'uncategorized' category
localhost:8000/wp-json/wp/v2/tags ...should be empty, no tags yet
localhost:8000/wp-json/wp/v2/users ...list the user added during installation
Testing with curl
curl GET test
curl -X GET localhost:8000/wp-json/wp/v2/categories/
[
{
"id":1,
"count":1,
"description":"",
"link":"http:\/\/localhost:8000\/category\/uncategorized\/",
"name":"Uncategorized",
"slug":"uncategorized",
"taxonomy":"category",
"parent":0,
"meta":[
],
"_links":{
"self":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/categories\/1"
}
],
"collection":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/categories"
}
],
"about":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/taxonomies\/category"
}
],
"wp:post_type":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/posts?categories=1"
}
],
"curies":[
{
"name":"wp",
"href":"https:\/\/api.w.org\/{rel}",
"templated":true
}
]
}
}
]
OK that was successful, next up try to POST some data.
curl simple POST test
curl -X POST "localhost:8000/wp-json/wp/v2/tags?name=friends&slug=friends&description=friendly%20friends"
{
"code":"rest_cannot_create",
"message":"Sorry, you are not allowed to create new terms.",
"data":{
"status":401
}
}
The simple POST test failed, essentially saying that the anonymous user is not allowed to update.
Add Basic Authentication
There is a basic-auth plug-in for Wordpress. Note this plugin should only be used for development purposes.
- download from github.com/eventespresso/Basic-Auth
- copy contents (basic-auth.php, composer.json) to folder wp/wp-content/plugins/Basic-Auth
- login as admin at http://localhost:8000/wp-login.php
- go to admin ==> Plugins
- then Activate the "JSON Basic Authentication plugin"
Here's a basic POST test, adding a new category. Note that your user/password needs to be substituted. Also note the id that is returned ("id":4 in this case), as that will be used later:
curl --user user:password -X POST "localhost:8000/wp-json/wp/v2/categories?name=news&slug=news&description=News"
{
"id":4,
"count":0,
"description":"News",
"link":"http:\/\/localhost:8000\/category\/news\/",
"name":"news",
"slug":"news",
"taxonomy":"category",
"parent":0,
"meta":[
],
"_links":{
"self":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/categories\/4"
}
],
"collection":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/categories"
}
],
"about":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/taxonomies\/category"
}
],
"wp:post_type":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/posts?categories=4"
}
],
"curies":[
{
"name":"wp",
"href":"https:\/\/api.w.org\/{rel}",
"templated":true
}
]
}
}
Now that the basic authentication plugin is activated, it can be used for POST, PUT, DELETE transactions.
curl POST Add new user
Here's another test, adding a new user:
curl --user user:password -X POST "localhost:8000/wp-json/wp/v2/users/" -H "Content-Type: application/json" -d '{"username":"test","email":"[email protected]","password":"testing"}'
{
"id":3,
"username":"test",
"name":"test",
"first_name":"",
"last_name":"",
"email":"[email protected]",
"url":"",
"description":"",
"link":"http:\/\/localhost:8000\/author\/test\/",
"locale":"en_US",
"nickname":"test",
"slug":"test",
"roles":[
"subscriber"
],
"registered_date":"2017-07-14T18:23:02+00:00",
"capabilities":{
"read":true,
"level_0":true,
"subscriber":true
},
"extra_capabilities":{
"subscriber":true
},
"avatar_urls":{
"24":"http:\/\/2.gravatar.com\/avatar\/55502f40dc8b7c769880b10874abc9d0?s=24&d=mm&r=g",
"48":"http:\/\/2.gravatar.com\/avatar\/55502f40dc8b7c769880b10874abc9d0?s=48&d=mm&r=g",
"96":"http:\/\/2.gravatar.com\/avatar\/55502f40dc8b7c769880b10874abc9d0?s=96&d=mm&r=g"
},
"meta":[
],
"_links":{
"self":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/users\/3"
}
],
"collection":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/users"
}
]
}
}
curl POST Add new post
Here's another test, adding a minimal new post. In this case, the post created also has the "id":4
curl --user user:password -X POST "localhost:8000/wp-json/wp/v2/posts/" -H "Content-Type: application/json" -d '{"title":"My 1st Post","content":"My Content","excerpt":"My Excerpt"}'
{
"id":4,
"date":"2017-07-14T18:48:20",
"date_gmt":"2017-07-14T18:48:20",
"guid":{
"rendered":"http:\/\/localhost:8000\/?p=4",
"raw":"http:\/\/localhost:8000\/?p=4"
},
"modified":"2017-07-14T18:48:20",
"modified_gmt":"2017-07-14T18:48:20",
"password":"",
"slug":"",
"status":"draft",
"type":"post",
"link":"http:\/\/localhost:8000\/?p=4",
"title":{
"raw":"My 1st Post",
"rendered":"My 1st Post"
},
"content":{
"raw":"My Content",
"rendered":"<p>My Content<\/p>\n",
"protected":false
},
"excerpt":{
"raw":"My Excerpt",
"rendered":"<p>My Excerpt<\/p>\n",
"protected":false
},
"author":4,
"featured_media":0,
"comment_status":"open",
"ping_status":"open",
"sticky":false,
"template":"",
"format":"standard",
"meta":[
],
"categories":[
1
],
"tags":[
],
"_links":{
"self":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/posts\/4"
}
],
"collection":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/posts"
}
],
"about":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/types\/post"
}
],
"author":[
{
"embeddable":true,
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/users\/4"
}
],
"replies":[
{
"embeddable":true,
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/comments?post=4"
}
],
"version-history":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/posts\/4\/revisions"
}
],
"wp:attachment":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/media?parent=4"
}
],
"wp:term":[
{
"taxonomy":"category",
"embeddable":true,
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/categories?post=4"
},
{
"taxonomy":"post_tag",
"embeddable":true,
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/tags?post=4"
}
],
"curies":[
{
"name":"wp",
"href":"https:\/\/api.w.org\/{rel}",
"templated":true
}
]
}
}
curl PUT Update and existing post
Here's another test, updating the created post (id 4) with the new category (id 4).
curl --user user:password -X PUT "localhost:8000/wp-json/wp/v2/posts/4?categories=4"
{
"id":4,
"date":"2017-07-14T19:08:06",
"date_gmt":"2017-07-14T19:08:06",
"guid":{
"rendered":"http:\/\/localhost:8000\/?p=4",
"raw":"http:\/\/localhost:8000\/?p=4"
},
"modified":"2017-07-14T19:08:06",
"modified_gmt":"2017-07-14T19:08:06",
"password":"",
"slug":"",
"status":"draft",
"type":"post",
"link":"http:\/\/localhost:8000\/?p=4",
"title":{
"raw":"My 1st Post",
"rendered":"My 1st Post"
},
"content":{
"raw":"My Content",
"rendered":"<p>My Content<\/p>\n",
"protected":false
},
"excerpt":{
"raw":"My Excerpt",
"rendered":"<p>My Excerpt<\/p>\n",
"protected":false
},
"author":4,
"featured_media":0,
"comment_status":"open",
"ping_status":"open",
"sticky":false,
"template":"",
"format":"standard",
"meta":[
],
"categories":[
4
],
"tags":[
],
"_links":{
"self":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/posts\/4"
}
],
"collection":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/posts"
}
],
"about":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/types\/post"
}
],
"author":[
{
"embeddable":true,
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/users\/4"
}
],
"replies":[
{
"embeddable":true,
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/comments?post=4"
}
],
"version-history":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/posts\/4\/revisions"
}
],
"wp:attachment":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/media?parent=4"
}
],
"wp:term":[
{
"taxonomy":"category",
"embeddable":true,
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/categories?post=4"
},
{
"taxonomy":"post_tag",
"embeddable":true,
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/tags?post=4"
}
],
"curies":[
{
"name":"wp",
"href":"https:\/\/api.w.org\/{rel}",
"templated":true
}
]
}
}
And the result showing in the list of posts, with the newly assigned "news" category:
curl POST Add new image file
This test adds an image to the Wordpress media collection:
curl --request POST \
--url http://localhost:8000/wp-json/wp/v2/media \
--user user:password \
--header "cache-control: no-cache" \
--header "content-disposition: attachment; filename=george.png" \
--header "content-type: image/png" \
--data-binary "@$HOME/Desktop/george.png" \
--location
{
"id":6,
"date":"2017-07-14T22:32:54",
"date_gmt":"2017-07-14T22:32:54",
"guid":{
"rendered":"http:\/\/localhost:8000\/wp-content\/uploads\/2017\/07\/george.png",
"raw":"http:\/\/localhost:8000\/wp-content\/uploads\/2017\/07\/george.png"
},
"modified":"2017-07-14T22:32:54",
"modified_gmt":"2017-07-14T22:32:54",
"slug":"george",
"status":"inherit",
"type":"attachment",
"link":"http:\/\/localhost:8000\/george\/",
"title":{
"raw":"george",
"rendered":"george"
},
"author":4,
"comment_status":"open",
"ping_status":"closed",
"template":"",
"meta":[
],
"description":{
"raw":"",
"rendered":"<p class=\"attachment\"><a href='http:\/\/localhost:8000\/wp-content\/uploads\/2017\/07\/george.png'><img width=\"300\" height=\"300\" src=\"http:\/\/localhost:8000\/wp-content\/uploads\/2017\/07\/george-300x300.png\" class=\"attachment-medium size-medium\" alt=\"\" srcset=\"http:\/\/localhost:8000\/wp-content\/uploads\/2017\/07\/george-300x300.png 300w, http:\/\/localhost:8000\/wp-content\/uploads\/2017\/07\/george-150x150.png 150w, http:\/\/localhost:8000\/wp-content\/uploads\/2017\/07\/george-100x100.png 100w, http:\/\/localhost:8000\/wp-content\/uploads\/2017\/07\/george.png 500w\" sizes=\"100vw\" \/><\/a><\/p>\n"
},
"caption":{
"raw":"",
"rendered":""
},
"alt_text":"",
"media_type":"image",
"mime_type":"image\/png",
"media_details":{
"width":500,
"height":500,
"file":"2017\/07\/george.png",
"sizes":{
"thumbnail":{
"file":"george-150x150.png",
"width":150,
"height":150,
"mime_type":"image\/png",
"source_url":"http:\/\/localhost:8000\/wp-content\/uploads\/2017\/07\/george-150x150.png"
},
"medium":{
"file":"george-300x300.png",
"width":300,
"height":300,
"mime_type":"image\/png",
"source_url":"http:\/\/localhost:8000\/wp-content\/uploads\/2017\/07\/george-300x300.png"
},
"twentyseventeen-thumbnail-avatar":{
"file":"george-100x100.png",
"width":100,
"height":100,
"mime_type":"image\/png",
"source_url":"http:\/\/localhost:8000\/wp-content\/uploads\/2017\/07\/george-100x100.png"
},
"full":{
"file":"george.png",
"width":500,
"height":500,
"mime_type":"image\/png",
"source_url":"http:\/\/localhost:8000\/wp-content\/uploads\/2017\/07\/george.png"
}
},
"image_meta":{
"aperture":"0",
"credit":"",
"camera":"",
"caption":"",
"created_timestamp":"0",
"copyright":"",
"focal_length":"0",
"iso":"0",
"shutter_speed":"0",
"title":"",
"orientation":"0",
"keywords":[
]
}
},
"post":null,
"source_url":"http:\/\/localhost:8000\/wp-content\/uploads\/2017\/07\/george.png",
"_links":{
"self":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/media\/6"
}
],
"collection":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/media"
}
],
"about":[
{
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/types\/attachment"
}
],
"author":[
{
"embeddable":true,
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/users\/4"
}
],
"replies":[
{
"embeddable":true,
"href":"http:\/\/localhost:8000\/wp-json\/wp\/v2\/comments?post=6"
}
]
}
}
And the result showing in the list of media items, with the newly uploaded "george" image: