Ywaarde / wordpress_orm

A Python wrapper around the WordPress JSON API.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

wordpress_orm

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 of User 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.

Examples

Connecting to the API

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.

Retrieving Posts

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()

Accessing Entity Elements

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']

Direct Access to Entities

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)

HTTP Session Reuse

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

Exception Handling

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!

Caveats

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.

User Queries

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).

About

A Python wrapper around the WordPress JSON API.

License:MIT License


Languages

Language:Python 95.1%Language:Shell 4.9%