teaming up wordpress api with backbone.js in titanium
TRANSCRIPT
TEAMING UP WP API & BACKBONE.JS IN TITANIUM
WHO KNOWS…
RFC 7230 - 7235
MAYBE THIS ONE…
RFC 2616
FAMILIAR WITH THIS?
HTTP
… AND THIS GUY?
-RFC 7230 - 7235
=RFC 2616
HTTPBIS
+HTTPBIS
=?
WHO THINKS HE/SHE KNOWS…?
REST
HTTP VERBS 101
CREATE POST /POSTS
RETRIEVE GET /POSTS[/X]
UPDATE PUT /POSTS/X
DELETE DELETE /POSTS/X
HTTP STATUSES 101
2XX SUCCESS ALL IS COOL!
3XX REDIRECTION GO OVER THERE!
4XX CLIENT ERROR YOU SCREWED UP!
5XX SERVER ERROR WE SCREWED UP!
WORDPRESS.ORG/PLUGINS/REST-API/
WP API
WP-API.ORG
COMPOSER REQUIRE WPACKAGIST/REST-API
/WP-JSON
{ "name": “A WP Site", "URL": “https://www.a-wp-site.nl”, "namespaces": [ ... ], "authentication": [] "routes": { "/": { ... }, “/wp/v2/posts”: { ... }, “/wp/v2/posts/<id>”: { ... }, ... “/wp/v2/users”: { ... }, “/wp/v2/users/<id>”: { ... }, “/wp/v2/users/me”: { ... }, ... “/wp/v2/media”: { ... } } }
/WP-JSON (DETAIL)
{ ... “/wp/v2/posts/<id>”: { "supports": [ "HEAD", "GET", "POST", "PUT", "PATCH", "DELETE" ], "accepts_json": true }, ... }
/WP-JSON/WP/V2/POSTS
POST /wp-json/wp/v2/posts HTTP/1.1 Host: www.a-wp-site.nl Authorization: Bearer anZitsafake6NjU0MzIx Content-Type: application/x-www-form-urlencoded
title=test&content_raw=test
/WP-JSON/WP/V2/POSTS
§ POSTS § PAGES § POST / PAGE META § POST / PAGE REVISIONS § POST TYPES § USERS § STATUSES § MEDIA § TAXONOMIES § TERMS CATEGORIES / TERMS TAGS § COMMENTS
OUT OF THE BOX SUPPORT
QUESTIONS?
THAT’S IT!
SIDE PROJECT : LOKALER
YOU KNOW HOW TO CREATE A PLUGIN?
EXTENDING THE API
MY PLUGIN.PHP SETUP
<?php /* Plugin Name: MY REST API Plugin URI: https://www.a-wp-site.nl/ Description: WP 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('REST_API_VERSION')) { // return early if WP API does not exist add_action('all_admin_notices', [$this, 'showError']);
return; } }
EXPOSE YOUR OWN CUSTOM POST TYPE
public function initServer() { //... add_action('rest_api_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'; }
ATTENTION PLEASE!
WP API TEAM HAS DONE A HUGE JOB
VERSION 1.XJSON_
JSON != RESTJSON_REST_API VS REST_API
V2 BETAREST_
IN CORE FOR WP 4.4SINCE OCTOBER 8TH
CHANGE WP_JSON INTO …
public function initServer() { if (!defined('REST_API_VERSION')) { // return early if WP API versions do not exist add_action('all_admin_notices', [$this, 'showError']);
return; }
add_filter('rest_url_prefix', [$this, 'changeApiBase']); }
public function changeApiBase() { return 'api'; }
NAMESPACES
{ "name": "A WP Site", "description": "", "URL": "https://www.a-wp-site.nl", "namespaces": [ "wp/v2", "your_namespace" ], "authentication": [] "routes": { "/": { ... }, "/wp/v2/posts": { ... }, ... "/your_namespace/path": { ... } } }
EXTEND EXPOSURE OF CUSTOM POST TYPE
public function initServer() { add_action('rest_api_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'; $wp_post_types['advertisement']->rest_controller_class = 'Lokaler\Api\Endpoint\Advertisement'; }
class Advertisement extends \WP_REST_Posts_Controller {}
EXTEND THE INPUT / OUTPUT
register_api_field('advertisement', 'price', [ 'schema' => [ 'type' => 'integer', 'context' => ['view', 'edit'], ], 'get_callback' => [$this, 'getMetaField'], 'update_callback' => [$this, 'saveMetaField'] ]);
public function getMetaField($post, $key) { return get_post_meta($post['id'], $key, true); }
public function saveMetaField($value, $post, $key) { return update_post_meta($post->ID, $key, $value); }
ADD YOUR OWN ROUTE
register_rest_route('khl', '/version/(?P<os>[a-z]{3,7})', [ [ 'methods' => WP_REST_Server::READABLE, 'callback' => [$this, 'getVersion'], 'permission_callback' => [$this, 'checkAccess'], 'args' => [ 'os' => [ 'validate_callback' => [$this, 'isOS'], 'sanitize_callback' => [$this, 'filterOS'], 'required' => true, ], ], ], ]);
WORDPRESS.ORG/PLUGINS/OAUTH2-PROVIDER/
AUTHORISATION
WP-OAUTH.COM
COMPOSER REQUIRE WPACKAGIST/OAUTH2-PROVIDER
APPCELERATOR TITANIUM
VERY GLOBAL OVERVIEW
xml + tss + js ALLOY
JAVASCRIPT
proxy modules TITANIUM SDK hyperloop
ANDROID IOS WINDOWS
BACKBONE.JS
BACKBONE DATA METHODS
SAVE POST /POSTS
FETCH GET /POSTS[/X]
SAVE PUT /POSTS/X
DESTROY DELETE /POSTS/X
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();
§ ‘FETCH’ a MODEL or COLLECTION § ‘DESTROY’ a MODEL § ‘CHANGE’ an ATTRIBUTE of a MODEL § ‘ADD’ a MODEL to a COLLECTION § ‘REMOVE’ a MODEL from a COLLECTION § ‘RESET’ a COLLECTION § ‘ERROR’ on MODEL or COLLECTION request at server § ‘INVALID’ MODEL provided
BACKBONE EVENTS IN TITANIUM
QUERY DATA FROM WORDPRESS
var advertisements = Alloy.Collections.instance(‘advertisement');
advertisements.fetch({ urlparams: { // https://codex.wordpress.org/Class_Reference/WP_Query filter: { posts_per_page: 3, orderby: {'date': 'DESC', 'ID': 'DESC'} }, page: 1 }, sql: { orderBy: 'timestamp DESC, id DESC' }, success: function (col) {
} });
EXTEND BACKBONE WITH REST BASED SQLITE STORAGE
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; } } } //... };
IF MODIFIED SINCEGET_LASTPOSTMODIFIED
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());
CREATING AN ADVERTISEMENT
var ad = Alloy.createModel('advertisement'); ad.set('title', 'This is the title'); ad.set('content', 'This is the description'); ad.save( {}, { success: function(response) {}, error: function(error, response) {} } );
MAGIC MINUSNEGATIVE INTEGERS
THE END RESULT