teaming up wordpress api with backbone.js in titanium
TRANSCRIPT
HTTP VERBS 101
CREATE POST SINGLE
RETRIEVE GET REPEATABLE
UPDATE PUT REPEATABLE
DELETE DELETE REPEATABLE
HTTPS://WORDPRESS.ORG/PLUGINS/JSON-REST-API/
WP API
WP-API.ORG
COMPOSER REQUIRE WPACKAGIST/JSON-REST-API
/WP-JSON
{ "name": “A WP Site", "description": "", "URL": “https://www.a-wp-site.nl”, "routes": { "/": { ... }, "/posts": { ... }, "/posts/<id>": { ... }, ... "/users": { ... }, "/users/<id>": { ... }, "/users/me": { ... }, ... "/media": { ... } }, "authentication": [] }
/WP-JSON (DETAIL)
{ ... "/posts/<id>": { "supports": [ "HEAD", "GET", "POST", "PUT", "PATCH", "DELETE" ], "accepts_json": true }, ... }
/WP-JSON/POSTS
POST /wp-json/posts HTTP/1.1 Host: www.a-wp-site.nl Authorization: Basic anZitsafake6NjU0MzIx Content-Type: application/x-www-form-urlencoded
title=test&content_raw=test
MY PLUGIN.PHP SETUP
<?php /* Plugin Name: MY JSON API Plugin URI: https://www.a-wp-site.nl/ Description: JSON REST API EXTENSION Version: 1.0 Author: JRDK Author URI: http://jrdk.nl */ require_once('src/Bootstrap.php');
new \Bootstrap();
WHEN TO TRIGGER YOUR CODE
public function __construct() { add_action('plugins_loaded', [$this, 'initServer'], 100); }
public function initServer() { if (!defined('JSON_API_VERSION')) { // return early if WP API does not exist add_action('all_admin_notices', [$this, 'showError']);
return; } }
ADD YOUR OWN CUSTOM POST TYPE
public function initServer() { //... add_action('wp_json_server_before_serve', [$this, 'initEndpoints']); }
public function initEndpoints($wp_json_server) { $ad = new Advertisement($wp_json_server); }
class Advertisement extends WP_JSON_CustomPostType { protected $base = '/advertisements'; protected $type = 'advertisement'; }
/WP-JSON/VERSION/IOS
public function __construct() { add_filter('json_endpoints', [$this, 'registerRoutes']); }
public function registerRoutes($routes) { $version_route = [ '/version/(?P<os>[a-z]{3,7})' => [ [ [$this, 'getVersion'], WP_JSON_Server::READABLE ], ], ]; return array_merge($routes, $version_route); }
BACK TO THE PLUGIN SETUP
public function initServer() { if (!defined('JSON_API_VERSION') || !defined('REST_API_VERSION')) { // return early if WP API versions do not exist add_action('all_admin_notices', [$this, 'showError']);
return; }
add_action('wp_json_server_before_serve', [$this, 'initEndpoints']); add_filter('rest_url_prefix', [$this, 'changeApiBase']); }
public function changeApiBase() { return 'api'; }
/API
{ "name": “A WP Site", "description": "", "URL": “https://www.a-wp-site.nl”, "routes": { "/": { ... }, “/wp/v2/posts”: { ... }, “/wp/v2/posts/<id>”: { ... }, ... “/wp/v2/users”: { ... }, “/wp/v2/users/<id>”: { ... }, “/wp/v2/users/me”: { ... }, ... “/wp/v2/media”: { ... } }, "authentication": [] }
EXPOSE CUSTOM POST TYPE
public function initServer() { //... add_action('init', [$this, 'updateExposure'], 12); }
public function updateExposure() { global $wp_post_types;
$wp_post_types['advertisement']->show_in_rest = true; $wp_post_types['advertisement']->rest_base = 'advertisement'; }
/API/KHL/VERSION/IOS
register_rest_route('khl', '/version/(?P<os>[a-z]{3,7})', [ 'callback' => [$this, 'getVersion'], 'methods' => \WP_REST_Server::READABLE, 'args' => [ 'context' => [ 'default' => 'view', ], ]] );
VERY GLOBAL OVERVIEW
xml + tss + js ALLOY
JAVASCRIPT
TITANIUM SDK + your own modules
ANDROID IOS WINDOWS
THAT’S IT… AGAIN
var post = Backbone.Model.extend({ urlRoot: '/api/wp/v2/posts' }); var posts = Backbone.Collection.extend({ model: post, url: '/api/wp/v2/posts' });
var newPost = new post({ title: ‘test', content_raw: ‘test' }); newPost.save();
BACKBONE TITANIUM EXTENSION
exports.definition = { config : { // table schema and adapter information }, extendModel: function(Model) { _.extend(Model.prototype, { // Extend, override or implement Backbone.Model }); return Model; }, extendCollection: function(Collection) { _.extend(Collection.prototype, { // Extend, override or implement Backbone.Collection }); return Collection; } }
CREATE SQLITE STORAGE WITH REST
exports.definition = { config: { columns: { id: 'INTEGER PRIMARY KEY', title: 'VARCHAR(50)', image: ‘TEXT', lastmodified: 'TEXT' }, URL: 'https://www.a-wp-site.nl/api/khl/advertisements', adapter: { type: 'sqlrest', collection_name: 'advertisements', idAttribute: 'id' } } //... };
PARSE WORDPRESS API DATA
exports.definition = { config: { //... parentNode: function(data) { if (_.isArray(data)) { var entries = []; _.each(data, function (_entry, index) { entries.push({ 'id': _entry.ID, 'title': _entry.title, 'image': _entry.featured_image }); }); return entries; } } } //... };
ALLOY VIEW EXAMPLE
<Alloy> <Collection src="advertisement"/> <Window class="container"> <ListView id="listing"> <Templates> <ItemTemplate name="fullItem"> <ImageView bindId="adImage" class="li-image" /> <Label bindId="title" class=“li-title"/> </ItemTemplate> </Templates> <ListSection dataCollection="advertisement"> <ListItem template="fullItem" itemId="{id}" title:text="{title}" adImage:image="{image}" /> </ListSection> </ListView> </Window> </Alloy>
QUERY DATA FROM WORDPRESS
var advertisements = Alloy.Collections.instance(‘advertisement');
advertisements.fetch({ urlparams: { filter: { posts_per_page: 3, orderby: {'date': 'DESC', 'ID': 'DESC'} }, page: 1 }, sql: { orderBy: 'timestamp DESC, id DESC' }, success: function (col) {
} });
UPLOADING A FILE
var bgImage = Ti.Filesystem.getFile('upload.jpg'); var xhr = Ti.Network.createHTTPClient();
xhr.timeout = 60000; xhr.open('POST', '/api/wp/v2/media'); xhr.setRequestHeader('Authorization', '...'); xhr.setRequestHeader('Content-Type', 'image/jpeg'); xhr.setRequestHeader( 'Content-Disposition', 'attachment; filename=upload.jpg' ); xhr.send(bgImage.read());