An object-oriented Python wrapper around the WordPress JSON API.
Aims for this module:
- Behave as an ORM (object-relational model). Queries return Python classes (e.g. a
Post
class), which then knows how to retrieve related objects (e.g.post.users
returns a list ofUser
objects). - Tightly wrapped around the Python Requests package, though usage does not depend on knowing anything about it.
- Unapologetically Python 3.x only.
- Written specifically against v2 of the WordPress JSON API, and specifically WordPress 4.7+.
This is a work in progress! The most significant feature not yet implemented is authentication. This is in active development (and being used in code), but should be considered "alpha" quality. Anything may change at any time.
Create an object that contains connection information to the WordPress site. All interaction will occur through this wordpress_orm.API
object.
import wordpress_orm as wp
# set up the connection
api = wp.API(url="https://demo.wp-api.org/wp-json/")
The Python objects (e.g.available properties) are closely tied to the WordPress API; keeping the reference page open as you code will be handy.
Use the PostRequest
object to retrieve posts from the API. Below we create a new PostRquest
directly from the api
object (which contains the connection information). We will retrieve all posts from the category "News" by specifying the slug for that category ('news').
post_request = api.PostRequest()
post_request.categories = ['news']
posts = post_request.get() # empty list returned if none found
The post API arguments are all defined in the PostRequest
Python object. For example, we can limit the posts to the most recent three:
post_request = api.PostRequest()
post_request.categories = ['news']
post_request.per_page = 3
post_request.orderby = "date"
post_request.order = "desc"
posts = post_request.get()
wordpress_orm
defines Python classes for each WordPress entity: Post
, PostRevision
, Category
, Tag
, Page
, Comment
, Taxonomy
, Media
, User
, PostType
, PostStatus
, Setting
. The WordPress API defines a schema for each entity. For example, the posts schema defines title
, author
, and category
.
wordpress_orm
defines a schema property s
through which you can access each element. For example, if you have a post
object as retrieved above, you can access the title as returned by the API with:
print(post.s.title)
Similarly, the author can be accessed:
print(post.s.author)
However, this is not very useful: the value returned by the API here is the author ID (just an integer). The Post
object has a property named author
that returns an User
Python object; behind the scenes, another API call will be made to create the entity.
# get the name of the author from a post
print("{0} {1}".format(post.author.s.first_name, post.author.s.first_name))
This is the reason for the s
property: it keeps the WordPress schema properties in a separate name space from more user(Python)-friendly properties, even if they share the same name. For example:
>>> post.s.categories
[1,6]
>>> post.categories
[<WP Category object at 0x7fd6932cd780 name='Blog'>, <WP Category object at 0x7fd6932cdb70 name='News'>]
>>> [cat.s.name for cat in post.categories]
['Blog', 'News']
For simple access to known entities, sometimes the search request objects are more than you need. For example, if you already know the ID of a particular post, the API provides an interface to instantiate it directly:
post12 = api.post(id=12)
These methods always return a single object. Entities can be retrieved by different (limited) properties:
post_vineger_review = api.post(slug='vinegar-review')
blog_category = api.category(slug='blog')
news_category = api.category(id=4)
It is apparent that by calling a related property from an entity (e.g. post.comments
) requires one or more trips to the server. The overhead of opening and closing numerous connections can get "expensive". The wordpress_orm
provides a way to take advantage of reusing a requests
session from within a context manager:
import wordpress_orm
from wordpress_orm import wp_session
api = wp.API(url="https://demo.wp-api.org/wp-json/")
with wp_session(api):
post12 = api.post(id=12)
# perform all queries inside this block
# work with data here after the shared session is closed
wordpress_orm
provides a few custom exceptions for error handling.
import wordpress_orm
try:
post12 = api.post(id=12)
except wordpress_orm.exc.NoEntityFound:
# handle post not found
try:
post12 = api.post(id=12)
except wordpress_orm.exc.AuthenticationRequired:
# not yet supported, coming soon!
The WordPress API is a wrapper around PHP functions that are part of WordPress. Ideally the API would not expose this detail, but there are a few holes in the documentation (and the API for that matter) that require one to reference the underlying code. The information below is useful for a developer of wordpress_orm
and should help when dealing with these cases. Any user of the code can ignore this section.
The search
parameter of the User
query is documented as “Limit results to those matching a string.” but doesn't provide further detail. The underlying code is a PHP function called WP_User_Query that tries to guess which column to search (actual code here). It takes an additional parameter called search_columns
to specificy which columns to search. Possible values are:
ID
- Search by user id.user_login
- Search by user login.user_nicename
- Search by user nicename.user_email
- Search by user email.user_url
- Search by user url.
In practice, search_columns
apprears to be ignored via the API.
GitHub issue: WP-API/docs#26 (link).