Advertisement
Advertisement

More Related Content

Advertisement

WordPress as the Backbone(.js)

  1. WORDPRESS AS THE BACKBONE(.JS)
  2. https://github.com/beaulebens/WROPE ! @beaulebens ! #wctoga
  3. BEAU LEBENS AUTOMATTIC O2
  4. WORDPRESS IS FOR BLOGS
  5. WORDPRESS IS FOR WEBSITES
  6. WORDPRESS IS A CMS
  7. WORDPRESS IS A PUBLISHING PLATFORM
  8. WORDPRESS IS AN APPLICATION BACKEND
  9. WORDPRESS.COM REST API https://developer.wordpress.com/
  10. JSON REST API https://wordpress.org/plugins/json-rest-api/
  11. JSON
  12. JavaScript Object Notation
  13. REST
  14. REpresentational State Transfer
  15. POST (create) GET (read) PUT (update) DELETE (delete)
  16. http://example.com/wp-json/posts/123/comments
  17. API
  18. Application Programming Interface
  19. API JSON “Programmatic access to your content in a universal format via simple HTTP requests” REST
  20. • Read and Write (when authenticated) • Perform “all” operations • Any system that talks HTTP + JSON
  21. LET’S BUILD AN APP! • Mobile first, obvs • Lightweight/lean (mobile is slow) • The web is cool, so we’ll use web technologies • Developer with no WordPress/PHP experience
  22. WROPE WordPress River Of Posts Experiment
  23. JAVASCRIPT?
  24. BACKBONE.JS • Helps write structured and sane client-side web apps • Relatively unopinionated/non-prescriptive • Basic building blocks for better web apps • Packages Underscore.js for great helper utilities • Bundled with WP core • Small (6.5kb! But that’s a bit deceptive, as we’ll see) • Lots of boilerplate (but very customizable)
  25. https://github.com/WP-API/client-js
  26. ROUTES routerObj: Backbone.Router.extend({ root: '/dev/WROPE/', ! routes: { '': 'index', ‘posts/:post’: 'post' }, ! index: function() { // Get a collection of posts from WP and render them once returned WROPE.fetchPosts( function() { this.renderRiver(); }.bind( this ) ); }, ! renderRiver: function() { WROPE.postsRiver = new WROPE.postsView( { collection: WROPE.posts } ); ! // Load optimized inline images, and reload them when the page is resized WROPE.optimizeImageSize(); $(window).on('resize', _.debounce( WROPE.optimizeImageSize, 500 ) ); }, ! post: function( post ) { if ( null === WROPE.posts ) { WROPE.fetchPosts( function() { this.renderPost( post ); }.bind( this ) ); } else { this.renderPost( post ); } }, ! renderPost: function( post ) { var thePost = WROPE.posts.get( post ); var postView = new WROPE.postView( { model: thePost, tagName: 'div' } ); $( '#wrope' ).slideUp( function() { $(this).html( postView.$el ).slideDown(); WROPE.optimizeImageSize(); }); return; } }), Application state via URIs
  27. • Keep track of where you are in your application • Allow for history management (Back button!) • Can use pushState or hash-based URIs • Fire events on matched routes • Fire callbacks based on their matched routes
  28. MODELS /** * Backbone model for single posts */ wp.api.models.Post = BaseModel.extend( _.extend( /** @lends Post.prototype */ { idAttribute: 'ID', ! urlRoot: WP_API_Settings.root + '/posts', ! defaults: { ID: null, title: '', status: 'draft', type: 'post', author: new wp.api.models.User(), content: '', link: '', 'parent': 0, date: new Date(), date_gmt: new Date(), modified: new Date(), modified_gmt: new Date(), format: 'standard', slug: '', guid: '', excerpt: '', menu_order: 0, comment_status: 'open', ping_status: 'open', sticky: false, date_tz: 'Etc/UTC', modified_tz: 'Etc/UTC', featured_image: null, terms: {}, post_meta: {}, meta: { links: {} } } }, TimeStampedMixin, HierarchicalMixin ) ); Structured key-value data stores (Post, Comment, etc)
  29. • Fire events when something changes • Keep track of changed values internally • Backed up by a REST API/endpoint (server magic!) • Have functions for converting to/from the expected model properties
  30. COLLECTIONS /** * Backbone collection for posts */ wp.api.collections.Posts = BaseCollection.extend( /** @lends Posts.prototype */ { url: WP_API_Settings.root + '/posts', List of models (Posts, Comments, etc) ! model: wp.api.models.Post } );
  31. • Bubble up model events • Fire their own events (add, remove, reset) • Have a ‘comparator’ to dynamically decide sort order • Have functions for filtering/retrieving specific models • Backed up by a REST API/endpoint
  32. VIEWS postView: Backbone.View.extend({ tagName: 'li', ! className: 'post', ! template: _.template( $('#tpl-post').text() ), ! events: { 'click a': 'preventDefault', 'click h1.post-title a': 'goToPage', 'click .featured-image a': 'goToPage' }, ! initialize: function( options ) { this.render(); }, ! preventDefault: function( e ) { e.preventDefault(); }, ! goToPage: function() { WROPE.router.navigate( '/' + this.model.get( 'ID' ), { trigger: true } ); return; }, ! render: function() { this.$el.html( this.template( this.model.attributes ) ); return this; } }), Visual representation of models/collections
  33. • Listen to events (on models/collections) and update appropriately • Handles interactions with the View (clicks etc) • Correspond to a DOM element (even if it’s not inserted into the page yet) • Are agnostic to your templating strategy
  34. SPEAKING OF TEMPLATES <script type="text/html" id="tpl-post"> <div class="post-header"> <div class="post-avatar"><img src="<%= author.attributes.avatar %>" width="40" height="40"></div> <h1 class="post-title"><a href="<%= link %>"><%= title %></a></h1> <div class="post-author"><%= author.name %></div> <div class="post-date"><%= date %></div> </div> <div class="post-body"> <% if ( featured_image ) { %> <div class="featured-image"> <a href="<%= link %>"> <img data-src="<%= photon( featured_image.source ) %>" alt="" class="feature"> </a> </div> <% } %> <%= excerpt %> </div> </script> HTML templates, delivered in the DOM as script tags
  35. • Built-in ERB-style in Underscore.js • Token-based replacements (with escaping) • Basic logic • Handlebars.js, Mustache.js, etc are also supported
  36. SIDELINE
  37. Routes Models Collections Views/Templates
  38. One more thing…
  39. <?php ! // One off hack to allow Cross Origin Resource Sharing from my laptop add_action( 'wp_json_server_before_serve', function() { // Allow my laptop to talk to WordPress header( 'Access-Control-Allow-Origin: http://beaurrito.local' ); ! // jQuery sends a preflight OPTIONS request to confirm control headers. // If that's what this request is, then after we've sent the above headers we can bail. if ( 'OPTIONS' == strtoupper( $_SERVER['REQUEST_METHOD'] ) ) { exit; } }); CORS HACK On your WP install (mu-plugins)
  40. CODE + DEMO
  41. https://github.com/beaulebens/WROPE ! Beau Lebens @beaulebens http://dntd.cc/
Advertisement