-
Notifications
You must be signed in to change notification settings - Fork 21
Adding Methods to the API
I am writing this page while actually adding a new feature to the API, this will be particularly in depth.
The first step is to open up classes/class-wc-json-api.php and find the function called public static function getImplementedMethods(), it will look similar to this:
<?php
public static function getImplementedMethods() {
if (self::$implemented_methods) {
return self::$implemented_methods;
}
self::$implemented_methods = array(
'get_system_time',
'get_products',
'get_categories',
'get_taxes',
'get_shipping_methods',
'get_payment_gateways',
'get_tags',
'get_products_by_tags',
'get_customers',
// Write capable methods
'set_products',
'set_categories',
);
return self::$implemented_methods;
}In this case, we will add the method "get_orders". All methods are named get|set_{resource}s. Since the API thinks ONLY IN COLLECTIONS.
We will modify it like so:
<?php
public static function getImplementedMethods() {
if (self::$implemented_methods) {
return self::$implemented_methods;
}
self::$implemented_methods = array(
'get_system_time',
'get_products',
'get_categories',
'get_taxes',
'get_shipping_methods',
'get_payment_gateways',
'get_tags',
'get_products_by_tags',
'get_customers',
'get_orders', // New Method
// Write capable methods
'set_products',
'set_categories',
);
return self::$implemented_methods;
}Here we have added the new method get_orders. We will need to scroll to the bottom of the file and add a method like so:
<?php
public function get_customers( $params ) {
global $wpdb;
blah blah blah
$this->result->setPayload($customers);
return $this->done();
}
public function get_orders( $params ) {
$posts_per_page = $this->helpers->orEq( $params['arguments'], 'per_page', 15 );
$paged = $this->helpers->orEq( $params['arguments'], 'page', 0 );
$ids = $this->helpers->orEq( $params['arguments'], 'ids', false);
... Your code will be here ...
$this->result->setPayload( $orders );
return $this->done();
}In this case, we added get_orders right after the function get_customers. Normally, we group functions of like kind together. So new methods for customers would be inserted after get_customers and before get_orders.
Always end the function with return $this->done(); This is a special method that takes care of preparing our results and returning them based on the configuration.
This is really all that is API specific. At this point, you can use any code you want to populate the $orders collection. It can be an array of arrays, or an array of objects, or models, or even string representations (Like CSV lines perhaps?) You are not limited in any way.
In this case, we will get a bit complicated. We will create an order model to help us out.
Models inherit from JSONAPIBaseRecord class.
<?php
/**
* A Product class to insulate the API from the details of the
* database representation
*/
require_once(dirname(__FILE__) . "/class-rede-base-record.php");
class WC_JSON_API_Order extends JSONAPIBaseRecord {
public static $_meta_attributes_table;
public static $_post_attributes_table;
private $_meta_attributes;
private $_post_attributes;
private $_status;
}We want to have as seamless as possible an interface between the API and the somewhat chaotic WP/WooCom backend. What we would consider a "Model" in OOP terms is generally split across at least two, and in the case of an order 3 different database tables. I imagine the WooCom team had something important in mind when they chose this method, it may have something to do with Wordpress' term API, but for humble/ignorant programmers like me, it's all much to sophisticated, I prefer a kind of stupid simplicity.
Because we want to abstract away the dirty business of updating, fetching, and creating records as much as possible and simply deal with collections, we will have to create a map of the attributes.
With Meta attributes and Post attributes, this is all very trivial, with an order, we will eventually have to deal with the status being saved as a term.
Here is our Map.
<?php
public static function setupMetaAttributes() {
if ( self::$_meta_attributes_table ) {
return;
}
// We only accept these attributes.
self::$_meta_attributes_table = array(
'order_key' => array('name' => '_order_key', 'type' => 'string'),
'billing_first_name' => array('name' => '_billing_first_name', 'type' => 'string'),
'billing_last_name' => array('name' => '_billing_last_name', 'type' => 'string'),
'billing_company' => array('name' => '_billing_company' , 'type' => 'string'),
'billing_address_1' => array('name' => '_billing_address_1', 'type' => 'string'),
'billing_address_2' => array('name' => '_billing_address_2', 'type' => 'string'),
'billing_city' => array('name' => '_billing_city', 'type' => 'string'),
'billing_postcode' => array('name' => '_billing_postcode', 'type' => 'string'),
'billing_country' => array('name' => '_billing_country', 'type' => 'string'),
'billing_state' => array('name' => '_billing_state', 'type' => 'string'),
'billing_email' => array('name' => '_billing_email', 'type' => 'string'),
'billing_phone' => array('name' => '_billing_phone', 'type' => 'string'),
'shipping_first_name' => array('name' => '_shipping_first_name', 'type' => 'string'),
'shipping_last_name' => array('name' => '_shipping_last_name' , 'type' => 'string'),
'shipping_company' => array('name' => '_shipping_company', 'type' => 'string'),
'shipping_address_1' => array('name' => '_shipping_address_1' , 'type' => 'string'),
'shipping_address_2' => array('name' => '_shipping_address_2', 'type' => 'string'),
'shipping_city' => array('name' => '_shipping_city', 'type' => 'string'),
'shipping_postcode' => array('name' => '_shipping_postcode', 'type' => 'string'),
'shipping_country' => array('name' => '_shipping_country', 'type' => 'string'),
'shipping_state' => array('name' => '_shipping_state', 'type' => 'string'),
'shipping_method' => array('name' => '_shipping_method' , 'type' => 'string'),
'shipping_method_title' => array('name' => '_shipping_method_title', 'type' => 'string'),
'payment_method' => array('name' => '_payment_method', 'type' => 'string'),
'payment_method_title' => array('name' => '_payment_method_title', 'type' => 'string'),
'order_discount' => array('name' => '_order_discount', 'type' => 'number'),
'cart_discount' => array('name' => '_cart_discount', 'type' => 'number'),
'order_tax' => array('name' => '_order_tax' , 'type' => 'number'),
'order_shipping' => array('name' => '_order_shipping' , 'type' => 'number'),
'order_shipping_tax' => array('name' => '_order_shipping_tax' , 'type' => 'number'),
'order_total' => array('name' => '_order_total', 'type' => 'number'),
'customer_user' => array('name' => '_customer_user', 'type' => 'number'),
'completed_date' => array('name' => '_completed_date', 'type' => 'datetime'),
'status' => array(
'name' => 'status',
'type' => 'string',
'getter' => 'getStatus',
'setter' => 'setStatus'
),
//'quantity' => array('name' => '_stock', 'type' => 'number', 'filters' => array('woocommerce_stock_amount') ),
);
/*
With this filter, plugins can extend this ones handling of meta attributes for a product,
this helps to facilitate interoperability with other plugins that may be making arcane
magic with a product, or want to expose their product extensions via the api.
*/
self::$_meta_attributes_table = apply_filters( 'woocommerce_json_api_order_meta_attributes_table', self::$_meta_attributes_table );
} // end setupMetaAttributesIn the code base, this is all well formatted, here it looks a bit chaotic at first, but is fairly transparent.This allows us to choose which Meta attributes we support, and how we handle them, it's more or less a copy/paste job. The only one of real interest here is:
<?php
'status' => array(
'name' => 'status',
'type' => 'string',
'getter' => 'getStatus',
'setter' => 'setStatus'
),This tells the system that we have a special getter/setter function defined, and that it should call this function when we try to access this attribute on the model.
The rest of them were just copy and pasted in.
Our next stop is to define the Post attributes, if this is indeed a "custom post type", later on we'll talk about handling Models that have their own table, such as OrderItems.
<?php
public static function setupPostAttributes() {
if ( self::$_post_attributes_table ) {
return;
}
self::$_post_attributes_table = array(
'name' => array('name' => 'post_title', 'type' => 'string'),
'guid' => array('name' => 'guid', 'type' => 'string'),
);
self::$_post_attributes_table = apply_filters( 'woocommerce_json_api_order_post_attributes_table', self::$_post_attributes_table );
}