Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
WORDPRESS REST API AND
ANGULARJS
FTW!
Roy Sivan and Josh Pollock
CalderaLearn.com
CalderaLabs.org
Join our Slack
LoopConf Slack: #workshop-wpapi
We will be posting links, taking
questions, and communicati...
CalderaLabs.org
Hi I'm Josh
Lead Developer: Caldera Labs
I make WordPress plugins
I teach about WordPress
I wrote a book a...
CalderaLearn.com
Hi, I'm Roy
Senior Software Engineer:
The Walt Disney Company
I am a member of The WP Crowd
I blog on roy...
What We're Covering Today
REST API 101
Building Custom REST APIs
Unit Testing Custom REST APIs
LUNCH BREAK
AngularJS (1.x)...
Educational Philosophy
All code is or is based on real world projects
We will show different ways of doing the same
thing....
Structure For Today
foreach ( $sections as $section ) :
Concepts / Lecture
Example Code Walkthrough (you will be cloning l...
WARNING
This workshop is to help you understand the basics
and some advanced technologies. Nothing will be
production read...
What you need for today
IDE or text editor (PHPStorm, Sublime, etc.)
Local WP install (VVV, DesktopServer, etc.)
npm
PHPUn...
CalderaLabs.org
0.
WordPress REST API?
Do we even need it?
CalderaLabs.org
NO
But you can build cool stuff with it.
It’s all about the Data
Data!
Data!
Data!
“
CalderaLearn.com
The API allows you to take WP data and put it in a
bucket. What you do with that bucket is up to you.
-...
CalderaLabs.org
What can we
build with it?
Facebooks? Myspaces?
API Powered Stuff
Things you can build that are powered by the API
Phone apps
Custom UI widgets on your site
Why use feed ...
CalderaLabs.org
1.
Custom REST APIs
With The WordPress REST API
CalderaLabs.org
Modify Default Routes
CalderaLabs.org
WordPress Gives Us
Routes
Which We Can Extend
CalderaLabs.org
Create Your Own Routes
CalderaLabs.org
Or We Can Make Our Own
With The Same Tools
How The REST API Works
WP_REST_Server ??WP_REST_Request WP_REST_Response
How The REST API Works
WP_REST_Server
Route
Callback
WP_REST_Request WP_REST_Response
ERROR!
ERROR!
CalderaLabs.org
Let's Talk About The
Orange Box
The Route Callback
Customizing The
Defaults
CalderaLabs.org
Extending Defaults
Adding Post Type
Support
add_action( 'init', 'my_book_cpt' );
function my_book_cpt() {
$labels = array(...);
$args = array(
...
'rest_controller_cl...
add_action( 'init', 'my_custom_post_type_rest_support', 25 );
function my_custom_post_type_rest_support() {
global $wp_pos...
CalderaLabs.org
Extending Defaults
Adding A Custom Field
CalderaLabs.org
Custom Field Is Any Data
Not just meta fields
function slug_get_meta_field( $object, $field_name, $request ) {
return get_post_meta( $object[ 'id' ], $field_name );
}
f...
add_action( 'rest_api_init', 'slug_register_spaceship' );
function slug_register_spaceship() {
register_api_field( 'post',...
CalderaLabs.org
Making Custom REST
APIs
The Basics
How It Works
add_action( 'rest_api_init', function () {
register_rest_route( 'myplugin/v1', '/author/(?P<id>d+)', array(
'methods' => '...
CalderaLabs.org
Creating Callback Class
Register Route(s)
class my_simple_route {
public function register_routes(){
$namespace = 'my-api/v1';
register_rest_route( $namespace, '/it...
class my_simple_route {
public function register_routes(){
...
register_rest_route( $namespace, '/items/(?P<id>d+)', [
'me...
CalderaLabs.org
Creating Callback Class
Defining Route Fields
register_rest_route( $this->namespace, '/items/(?P<id>d+)', [
...
'args' => [
'type' => [
'required' => true,
'validate_ca...
Registering Route(s) : Field Sanitization Callback
Use to ensure data is safe.
Defined using a callable.
Change data to a ...
Registering Route(s) : Field Validation Callback
Use to ensure data is correct.
Defined using a callable.
Used to reject i...
Registering Route(s) : Field Validation Callback
public function validate_type( $value ){
if( !in_array( $value, [ 'big', ...
CalderaLabs.org
Creating Callback Class
Permissions Callback
Registering Route(s) : Permissions Callback
Determine if user is authorized.
Return true or false
Registering Route(s) : Permissions Callback
Example: Make require login.
public function get_items_permissions(){
if( is_u...
Registering Route(s) : Permissions Callback
Example: Limit To Admins
public function get_items_permissions(){
if( current_...
Registering Route(s) : Permissions Callback
Example: Allow Always
public function get_items_permissions(){
return true;
}
CalderaLabs.org
Creating Callback Class
Route Callback Function
Registering Route(s) : Callback
Do something with the request
Gets an object of WP_REST_Request
Should return WP_REST_Resp...
WP_Rest_Response
Represents current request
Contains:
◇ Parameters
◇ Headers
No need to access $_GET, $_POST, $_REQUEST
Im...
Registering Route(s) : Callback
public function get_item( WP_REST_Request $request ){
$id = $request[ 'id' ];
$item = slug...
CalderaLabs.org
Initializing The Class
The rest_api_init action
CalderaLabs.org
rest_api_init
Use To Load Code Only
Needed In REST API Requests
Registering Route(s) : Initializing
add_action( 'rest_api_init', function(){
$route = new my_simple_route();
$route->regis...
CalderaLabs.org
2.
Unit Testing Custom
REST APIs
Subtitle
CalderaLearn.com
Goal
Only Test Our Endpoints
CalderaLabs.org
PHPUnit +
WP_UnitTestCase
CalderaLabs.org
Setting Up
Prepare To Test
Unit Testing 101
Make Sure Things Return What They Should Return
$this->assertEquals( 42, function_that_returns_42() );
$t...
Install PHPUnit
wget https://phar.phpunit.de/phpunit.phar
chmod +x phpunit.phar
mv phpunit.phar /usr/local/bin/phpunit
wge...
Install WP CLI
curl -O
https://raw.githubusercontent.com/wp-cli/builds/gh-pages/
phar/wp-cli.phar
php wp-cli.phar --info
c...
Initialize Unit Tests
wp scaffold plugin-tests
CalderaLabs.org
Writing Tests
Testing!
CalderaLearn.com
Mock
Requests
An Example
public function test_get_items_author_query() {
$this->factory->post->create( array( 'post_author' => 4 ) );
$t...
An Example
public function test_get_items_author_query() {
$this->factory->post->create( array( 'post_author' => 4 ) );
$t...
CalderaLearn.com
Test Case
Unit Test Case For REST API Endpoints
Create a reusable class that:
Create Instance of WP_REST_Server
Boot routes
Make sur...
Test Case Outline
class Test_API extends WP_UnitTestCase {
/** @var WP_REST_Server*/
protected $server;
protected $namespa...
Test Case: Set Up
protected $server;
public function setUp() {
parent::setUp();
/** @var WP_REST_Server $wp_rest_server */...
Test Case: Test Route Is Registered
public function test_register_route() {
$routes = $this->server->get_routes();
$this->...
Test Case: Test Endpoints Exist
public function test_endpoints() {
$the_route = $this->namespaced_route;
$routes = $this->...
CalderaLearn.com
Testing
Custom Routes
Test Your API Only!!!
Test internal logic elsewhere
Test control of that logic
Test response format
Trust core
Example Route Test
class Test_Hi extends Test_API {
protected $namespace = '/hi-api/v1/names';
public function test_list()...
Example Route Test
class Test_Hi extends Test_API {
protected $namespace = '/hi-api/v1/names';
public function test_single...
CalderaLabs.org
3.
Getting Started With
AngularJS 1.x
Controllers, Templates, Services & Factories
CalderaLabs.org
3 con’t
Why Angular?
You know it’s in the title of the workshop, right?
“
CalderaLearn.com
AngularJS is the best JavaScript Framework.
-- Roy Sivan
Senior WordPress Engineer at Disney (so you kn...
Not WordPress
To get you through the basics of
AngularJS we will be using
sample data, not WP
Our First Project
No npm or ...
Quicker & Easier
Quicker to get going to show
overall concepts.
Honest Truth
We already have a few projects
built in it th...
HTML powered JavaScript
With Angular 1.x you can use
HTML to do most things reserved
for PHP.
Get the data using JS, templ...
CalderaLearn.com
Step 1
Setup the APP
Setting up the app
All functionality lives within 1 app
We use ng-app to encapsulate the app in the DOM, it can be used on...
Sample Data JSON
data.json
This file is going to be a sample of data, that we are going to use to build out
a simple Angul...
Injectables
Injectables are objects which can be injected and used in
controllers, directives, etc.
We will be creating ou...
AngularJS Controllers
Controller is all about $scope
A Controller is defined by a JavaScript constructor function that is ...
All Together - JS
wpNG = {};
wpNG.app = ( function( app ){
console.log( 'initializing..' );
// define our app
app = angula...
All Together - HTML
<div ng-app="wpAngularApp" id="app-container">
<div ng-controller="listView">
<!-- List View -->
</div...
CalderaLearn.com
Step 2
HTML! Looping through the data
First we must get data
$http is a jQuery AJAX wrapper & returns a promise
$http({method: ‘’, url: ‘’})
$http.get(url)
$htt...
Say hello to JSON
JSON is the JavaScript Object Notation.
We display JSON with curly brackets
We work with JSON similar to...
The loop HTML
<div ng-controller="listView">
<h2>Posts</h2>
<!-- Loop through $scope.posts -->
<article ng-repeat="post in...
Add more data
<article ng-repeat="post in posts">
<img ng-src="{{post.image}}" />
<h2>{{post.title}}</h2>
<div
class="post...
CalderaLabs.org
4.
Decoupled Front-ends
With AngularJS
A site has no WordPress
Decoupled Front End
Decouple front end is a front end app that doesn’t live within
WordPress at all.
Your website: myaweso...
Decoupled Use Cases
Phone App
Piece of functionality that communicates with WP data
Advanced, Unique UI
Combine with other...
Our decoupled App
npm
gulp
REST url that is publicly accessible (we will give you one)
Tacos, you always need tacos.
What ...
CalderaLabs.org
What About CORS?
Cross-Origin Resource Sharing
CORS
Allows browsers to make requests across
domains.
IS NOT SECURITY!!
By default WordPress REST API is same-origin
only....
Allow All Domains For All Methods
add_action( 'rest_api_init', function() {
remove_filter( 'rest_pre_serve_request', 'rest...
Only Allow GET Requests
add_action( 'rest_api_init', function() {
remove_filter( 'rest_pre_serve_request', 'rest_send_cors...
Allows From Certain Origins
add_action( 'rest_api_init', function() {
remove_filter( 'rest_pre_serve_request', 'rest_send_...
CalderaLabs.org
Factories, Storage,
UI-Router, and
Templates
All the things!
AngularJS Factories
Factories allow you to create injectable objects.
Inject $resource into the factory it to create an ob...
AngularJS Factories cont’d
Posts.get()
Posts.query() - like get, but expects array
Posts.save()
Posts.delete()
Posts.remov...
Local Storage
https://github.com/grevory/angular-local-storage
An AngularJS module that gives you access to the browser’s ...
UI-Router
https://github.com/angular-ui/ui-router
The Angular-UI project adds modules and functionality to Angular (think ...
Templates
Separating out templates into templates directory
Cleaner code
Separation of views
1 controller can have 1 templ...
CalderaLabs.org
Now Entering
The Danger Zone
First thing is first
Clone the repo
You will need to run npm install and gulp
The config file
Create a file called config.js in /assets/js
var ngWP = ngWP || {};
ngWP.config = {
api: 'https://calderaf...
Stepping through the code
Main APP file
UI Router Definitions
Small controllers live here
Templates
Blog/Author List
Blog ...
CalderaLabs.org
5.
Plugin Admin Screens
With AngularJS
The UI Router
Making Mini-Apps To Make WordPress Better
Very Similar To
Regular NG App
Basic
Use add_admin_menu() to print basic HTML
Use ui-router to switch routes inside admin
page.
Use wp_localize_script() ...
Questions?
Use PHP or HTML files for templates?
How to handle translations?
wp_localize_script()
PHP templates
Let's Look At
Some Code!
What’s Next?
Angular 2 Theme currently in development
github.com/royboy789/Angular-Wordpress-Theme/tree/v7
Vue.JS - The ne...
Want more Roy & Josh teachings?
Caldera Learn teaches through 4-week live classroom
style webinars. Teachers are Josh and/...
CalderaLabs.org
Josh Pollock
JoshPress.net
CalderaForms.com
CalderaLearn.com
CalderaLabs.org
@Josh412
CalderaLabs.org
Roy Sivan
theWPCrowd.com
RoySivan.com
Lynda.com
CaldraLearn.com
@royboy789
CalderaLabs.org
Want To Learn More?
Coming Very Soon
CalderaLearn.com
Upcoming SlideShare
Loading in …5
×

Caldera Learn - LoopConf WP API + Angular FTW Workshop

11,301 views

Published on

The WordPress REST API combined with a JavaScript MVC framework opens up new possibilities for better, more intuitive interfaces that solve scaling and other challenges. In this workshop we will use AngularJS, the best — because we said so — and the WordPress REST API to create custom applications. First we will walk through creating custom API routes and endpoints to interact with your data, followed by two unique ways to use AngularJS to create better interfaces for your projects. This will include a decoupled front-end and single page web app as a plugin interface.

Published in: Technology
  • Be the first to comment

Caldera Learn - LoopConf WP API + Angular FTW Workshop

  1. 1. WORDPRESS REST API AND ANGULARJS FTW! Roy Sivan and Josh Pollock CalderaLearn.com
  2. 2. CalderaLabs.org Join our Slack LoopConf Slack: #workshop-wpapi We will be posting links, taking questions, and communicating throughout the day via Slack
  3. 3. CalderaLabs.org Hi I'm Josh Lead Developer: Caldera Labs I make WordPress plugins I teach about WordPress I wrote a book about the WordPress REST API I am a core contributor to WordPress I am a member of The WP Crowd
  4. 4. CalderaLearn.com Hi, I'm Roy Senior Software Engineer: The Walt Disney Company I am a member of The WP Crowd I blog on roysivan.com I teach on Lynda.com & CalderaLearn People say Hi to me a lot
  5. 5. What We're Covering Today REST API 101 Building Custom REST APIs Unit Testing Custom REST APIs LUNCH BREAK AngularJS (1.x) Basics Building Decoupled Front-ends Building Plugin Admin Screens
  6. 6. Educational Philosophy All code is or is based on real world projects We will show different ways of doing the same thing. Please ask why it's different ◇ we may give you a good answer Stop us and ask questions
  7. 7. Structure For Today foreach ( $sections as $section ) : Concepts / Lecture Example Code Walkthrough (you will be cloning locally) Hands-on DIY Group Walk Through Code Group endforeach;
  8. 8. WARNING This workshop is to help you understand the basics and some advanced technologies. Nothing will be production ready code.
  9. 9. What you need for today IDE or text editor (PHPStorm, Sublime, etc.) Local WP install (VVV, DesktopServer, etc.) npm PHPUnit (optional, included in VVV) Composer (optional) AngularJS Batarang Chrome Extension https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehid hipcmcojjgiloacoafjmpfk?hl=en
  10. 10. CalderaLabs.org 0. WordPress REST API? Do we even need it?
  11. 11. CalderaLabs.org NO But you can build cool stuff with it.
  12. 12. It’s all about the Data Data! Data! Data!
  13. 13. “ CalderaLearn.com The API allows you to take WP data and put it in a bucket. What you do with that bucket is up to you. -- Morten Rand Hendriksen @mor10
  14. 14. CalderaLabs.org What can we build with it? Facebooks? Myspaces?
  15. 15. API Powered Stuff Things you can build that are powered by the API Phone apps Custom UI widgets on your site Why use feed of another site, when you can API Custom Dashboards in the admin Custom WP Dashboard (YAS!) User role based dashboard
  16. 16. CalderaLabs.org 1. Custom REST APIs With The WordPress REST API
  17. 17. CalderaLabs.org Modify Default Routes
  18. 18. CalderaLabs.org WordPress Gives Us Routes Which We Can Extend
  19. 19. CalderaLabs.org Create Your Own Routes
  20. 20. CalderaLabs.org Or We Can Make Our Own With The Same Tools
  21. 21. How The REST API Works WP_REST_Server ??WP_REST_Request WP_REST_Response
  22. 22. How The REST API Works WP_REST_Server Route Callback WP_REST_Request WP_REST_Response ERROR! ERROR!
  23. 23. CalderaLabs.org Let's Talk About The Orange Box The Route Callback
  24. 24. Customizing The Defaults
  25. 25. CalderaLabs.org Extending Defaults Adding Post Type Support
  26. 26. add_action( 'init', 'my_book_cpt' ); function my_book_cpt() { $labels = array(...); $args = array( ... 'rest_controller_class' => 'WP_REST_Posts_Controller', 'show_in_rest' => true, 'rest_base' => 'books-api', ); register_post_type( 'book', $args ); } Add REST API Support To Post Type Registration
  27. 27. add_action( 'init', 'my_custom_post_type_rest_support', 25 ); function my_custom_post_type_rest_support() { global $wp_post_types; $post_type_name = 'book'; if( isset( $wp_post_types[ $post_type_name ] ) ) { $wp_post_types[$post_type_name]->show_in_rest = true; $wp_post_types[$post_type_name]->rest_base = $post_type_name; $wp_post_types[$post_type_name]->rest_controller_class = 'WP_REST_Posts_Controller'; } } Add REST API Support To An Existing Post Type
  28. 28. CalderaLabs.org Extending Defaults Adding A Custom Field
  29. 29. CalderaLabs.org Custom Field Is Any Data Not just meta fields
  30. 30. function slug_get_meta_field( $object, $field_name, $request ) { return get_post_meta( $object[ 'id' ], $field_name ); } function slug_update_meta( $value, $object, $field_name ) { if ( ! $value || ! is_string( $value ) ) { return; } return update_post_meta( $object->ID, $field_name, strip_tags( $value ) ); } Adding Custom Fields To A Response: Callbacks
  31. 31. add_action( 'rest_api_init', 'slug_register_spaceship' ); function slug_register_spaceship() { register_api_field( 'post', 'starship', array( 'get_callback' => 'slug_get_meta_field', 'update_callback' => 'slug_update_meta_field', ) ); } Adding Custom Fields To A Response: Registration
  32. 32. CalderaLabs.org Making Custom REST APIs The Basics How It Works
  33. 33. add_action( 'rest_api_init', function () { register_rest_route( 'myplugin/v1', '/author/(?P<id>d+)', array( 'methods' => 'GET', 'callback' => 'route_callback', ) ); } ); Registering A Route
  34. 34. CalderaLabs.org Creating Callback Class Register Route(s)
  35. 35. class my_simple_route { public function register_routes(){ $namespace = 'my-api/v1'; register_rest_route( $namespace, '/items', [ 'methods' => 'GET', 'callback' => [ $this, 'get_items' ], 'permissions_callback' => [ $this, 'get_items_permissions' ] ] ); ... } } Registering Route(s)
  36. 36. class my_simple_route { public function register_routes(){ ... register_rest_route( $namespace, '/items/(?P<id>d+)', [ 'methods' => 'GET', 'callback' => [ $this, 'get_item' ], 'permissions_callback' => [ $this, 'get_item_permissions' ] ] ); } } Registering Route(s)
  37. 37. CalderaLabs.org Creating Callback Class Defining Route Fields
  38. 38. register_rest_route( $this->namespace, '/items/(?P<id>d+)', [ ... 'args' => [ 'type' => [ 'required' => true, 'validate_callback' => [ $this, 'validate_type' ] ], 'number' => [ 'default' => 5, 'sanitize_callback' => 'absint' ] ] ] ); Registering Route(s) : Defining Fields
  39. 39. Registering Route(s) : Field Sanitization Callback Use to ensure data is safe. Defined using a callable. Change data to a safe value. Return prepared value
  40. 40. Registering Route(s) : Field Validation Callback Use to ensure data is correct. Defined using a callable. Used to reject invalid requests Return true or false
  41. 41. Registering Route(s) : Field Validation Callback public function validate_type( $value ){ if( !in_array( $value, [ 'big', 'small', 'very-small' ] ) ){ return false; } return true; }
  42. 42. CalderaLabs.org Creating Callback Class Permissions Callback
  43. 43. Registering Route(s) : Permissions Callback Determine if user is authorized. Return true or false
  44. 44. Registering Route(s) : Permissions Callback Example: Make require login. public function get_items_permissions(){ if( is_user_logged_in() ){ return true; } return false; }
  45. 45. Registering Route(s) : Permissions Callback Example: Limit To Admins public function get_items_permissions(){ if( current_user_can( 'manage_options' ) ){ return true; } return false; }
  46. 46. Registering Route(s) : Permissions Callback Example: Allow Always public function get_items_permissions(){ return true; }
  47. 47. CalderaLabs.org Creating Callback Class Route Callback Function
  48. 48. Registering Route(s) : Callback Do something with the request Gets an object of WP_REST_Request Should return WP_REST_Response or WP_Error
  49. 49. WP_Rest_Response Represents current request Contains: ◇ Parameters ◇ Headers No need to access $_GET, $_POST, $_REQUEST Implements Arrayaccess $request->param( 'field_name' ); $request[ 'field_name' ];
  50. 50. Registering Route(s) : Callback public function get_item( WP_REST_Request $request ){ $id = $request[ 'id' ]; $item = slug_crud_get( $id ); if( ! empty( $item ) && ! is_wp_error( $item ) ){ return rest_ensure_response( $item ); }elseif ( is_wp_error( $item ) ){ return $item; }else{ $response = new WP_REST_Response( 'No items found', 404 ); return $response; } }
  51. 51. CalderaLabs.org Initializing The Class The rest_api_init action
  52. 52. CalderaLabs.org rest_api_init Use To Load Code Only Needed In REST API Requests
  53. 53. Registering Route(s) : Initializing add_action( 'rest_api_init', function(){ $route = new my_simple_route(); $route->register_routes(); });
  54. 54. CalderaLabs.org 2. Unit Testing Custom REST APIs Subtitle
  55. 55. CalderaLearn.com Goal Only Test Our Endpoints
  56. 56. CalderaLabs.org PHPUnit + WP_UnitTestCase
  57. 57. CalderaLabs.org Setting Up Prepare To Test
  58. 58. Unit Testing 101 Make Sure Things Return What They Should Return $this->assertEquals( 42, function_that_returns_42() ); $this->assertSame( '42', function_that_returns_42() ); $this->assertArrayHasKey( 'roy', array( 'roy' => 'hi' ) ); Google: "Pippin Williamson Unit Tests for WordPress Plugins"
  59. 59. Install PHPUnit wget https://phar.phpunit.de/phpunit.phar chmod +x phpunit.phar mv phpunit.phar /usr/local/bin/phpunit wget https://phar.phpunit.de/phpunit.phar php phpunit.phar
  60. 60. Install WP CLI curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/ phar/wp-cli.phar php wp-cli.phar --info chmod +x wp-cli.phar sudo mv wp-cli.phar /usr/local/bin/wp
  61. 61. Initialize Unit Tests wp scaffold plugin-tests
  62. 62. CalderaLabs.org Writing Tests Testing!
  63. 63. CalderaLearn.com Mock Requests
  64. 64. An Example public function test_get_items_author_query() { $this->factory->post->create( array( 'post_author' => 4 ) ); $this->factory->post->create( array( 'post_author' => 4 ) ); $this->factory->post->create( array( 'post_author' => 2 ); $request = new WP_REST_Request( 'GET', '/wp/v2/posts' ); $response = $this->server->dispatch( $request ); $this->assertEquals( 200, $response->get_status() ); $this->assertEquals( 3, count( $response->get_data() ) ); }
  65. 65. An Example public function test_get_items_author_query() { $this->factory->post->create( array( 'post_author' => 4 ) ); $this->factory->post->create( array( 'post_author' => 4 ) ); $this->factory->post->create( array( 'post_author' => 2 ); $request = new WP_REST_Request( 'GET', '/wp/v2/posts' ); $request->set_param( 'author', 4 ); $response = $this->server->dispatch( $request ); $this->assertEquals( 200, $response->get_status() ); $this->assertEquals( 2, count( $response->get_data() ) ); }
  66. 66. CalderaLearn.com Test Case
  67. 67. Unit Test Case For REST API Endpoints Create a reusable class that: Create Instance of WP_REST_Server Boot routes Make sure route is booted
  68. 68. Test Case Outline class Test_API extends WP_UnitTestCase { /** @var WP_REST_Server*/ protected $server; protected $namespaced_route = 'caldera-forms/v1'; public function setUp() {} public function test_register_route() {} public function test_endpoints() {} }
  69. 69. Test Case: Set Up protected $server; public function setUp() { parent::setUp(); /** @var WP_REST_Server $wp_rest_server */ global $wp_rest_server; $this->server = $wp_rest_server = new WP_REST_Server; do_action( 'rest_api_init' ); }
  70. 70. Test Case: Test Route Is Registered public function test_register_route() { $routes = $this->server->get_routes(); $this->assertArrayHasKey( $this->namespaced_route, $routes ); }
  71. 71. Test Case: Test Endpoints Exist public function test_endpoints() { $the_route = $this->namespaced_route; $routes = $this->server->get_routes(); foreach( $routes as $route => $route_config ) { if( 0 === strpos( $the_route, $route ) ) { $this->assertTrue( is_array( $route_config ) ); foreach( $route_config as $i => $endpoint ) { $this->assertArrayHasKey( 'callback', $endpoint ); $this->assertArrayHasKey( 0, $endpoint[ 'callback' ], get_class( $this ) ); $this->assertArrayHasKey( 1, $endpoint[ 'callback' ], get_class( $this ) ); $this->assertTrue( is_callable( array( $endpoint[ 'callback' ][0], $endpoint[ 'callbac ][1] ) ) ); } } }
  72. 72. CalderaLearn.com Testing Custom Routes
  73. 73. Test Your API Only!!! Test internal logic elsewhere Test control of that logic Test response format Trust core
  74. 74. Example Route Test class Test_Hi extends Test_API { protected $namespace = '/hi-api/v1/names'; public function test_list() { $request = new WP_REST_Request( 'GET', $this->namespace ); $response = $this->server->dispatch( $request ); $this->assertEquals( 200, $response->get_status() ); $data = $response->get_data(); $this->assertArrayHasKey( 'name', $data[0] ); $this->assertEquals( 'shawn', $data[0][ 'name' ] ); $this->assertArrayHasKey( 'name', $data[1] ); $this->assertEquals( 'roy', $data[1][ 'name' ] ); } }
  75. 75. Example Route Test class Test_Hi extends Test_API { protected $namespace = '/hi-api/v1/names'; public function test_single(){ $request = new WP_REST_Request( 'GET', $this->namespace . '/roy' ); $response = $this->server->dispatch( $request ); $this->assertEquals( 200, $response->get_status() ); $data = $response->get_data(); $this->assertArrayHasKey( 'name', $data ); $this->assertEquals( 'roy', $data[ 'name' ] ); } }
  76. 76. CalderaLabs.org 3. Getting Started With AngularJS 1.x Controllers, Templates, Services & Factories
  77. 77. CalderaLabs.org 3 con’t Why Angular? You know it’s in the title of the workshop, right?
  78. 78. “ CalderaLearn.com AngularJS is the best JavaScript Framework. -- Roy Sivan Senior WordPress Engineer at Disney (so you know he is legit)
  79. 79. Not WordPress To get you through the basics of AngularJS we will be using sample data, not WP Our First Project No npm or gulp We aren’t using any build tools, this is a pure sample https://github.com/caldera-learn/angularjs-intro
  80. 80. Quicker & Easier Quicker to get going to show overall concepts. Honest Truth We already have a few projects built in it that are ready to go Why 1.x? 2 is in RC! Roy is lazy I am not lazy, but didn’t have time to learn it deeply enough yet to give a full workshop on it. Josh Switched Teams He used to be team NG1. Now he is team VueJS.
  81. 81. HTML powered JavaScript With Angular 1.x you can use HTML to do most things reserved for PHP. Get the data using JS, template with HTML. No PHP needed.
  82. 82. CalderaLearn.com Step 1 Setup the APP
  83. 83. Setting up the app All functionality lives within 1 app We use ng-app to encapsulate the app in the DOM, it can be used on any element including HTML. Using it on the HTML encapsulates the whole DOM
  84. 84. Sample Data JSON data.json This file is going to be a sample of data, that we are going to use to build out a simple Angular App, we will then replace it with the WordPress REST API
  85. 85. Injectables Injectables are objects which can be injected and used in controllers, directives, etc. We will be creating our own later...
  86. 86. AngularJS Controllers Controller is all about $scope A Controller is defined by a JavaScript constructor function that is used to augment the AngularJS Scope. When a Controller is attached to the DOM via the ng-controller directive, AngularJS will instantiate a new Controller object, using the specified Controller's constructor function All new data to be used must be stored within $scope.your_key ng-controller
  87. 87. All Together - JS wpNG = {}; wpNG.app = ( function( app ){ console.log( 'initializing..' ); // define our app app = angular.module('wpAngularApp', []) .controller( 'listView', ['$scope', '$http', function( $scope, $http ) { … }]); return app; }(wpNG.app || {});
  88. 88. All Together - HTML <div ng-app="wpAngularApp" id="app-container"> <div ng-controller="listView"> <!-- List View --> </div> </div>
  89. 89. CalderaLearn.com Step 2 HTML! Looping through the data
  90. 90. First we must get data $http is a jQuery AJAX wrapper & returns a promise $http({method: ‘’, url: ‘’}) $http.get(url) $http.post(url) Because it returns a promise we use .then()
  91. 91. Say hello to JSON JSON is the JavaScript Object Notation. We display JSON with curly brackets We work with JSON similar to PHP arrays {{Object.key}} displays that key value In PHP that would be $object[‘key’];
  92. 92. The loop HTML <div ng-controller="listView"> <h2>Posts</h2> <!-- Loop through $scope.posts --> <article ng-repeat="post in posts"> <h2>{{post.title}}</h2> </article> </div>
  93. 93. Add more data <article ng-repeat="post in posts"> <img ng-src="{{post.image}}" /> <h2>{{post.title}}</h2> <div class="post-content" ng-bind-html="post.content | to_trusted"> </div> </article>
  94. 94. CalderaLabs.org 4. Decoupled Front-ends With AngularJS A site has no WordPress
  95. 95. Decoupled Front End Decouple front end is a front end app that doesn’t live within WordPress at all. Your website: myawesomesite.com Decoupled: myawesomeapp.com - but running on the same data! How cool is that!
  96. 96. Decoupled Use Cases Phone App Piece of functionality that communicates with WP data Advanced, Unique UI Combine with other APIs Different Stack (decoupled app doesn’t need to be PHP)
  97. 97. Our decoupled App npm gulp REST url that is publicly accessible (we will give you one) Tacos, you always need tacos. What you will need: https://github.com/caldera-learn/decoupled-app
  98. 98. CalderaLabs.org What About CORS? Cross-Origin Resource Sharing
  99. 99. CORS Allows browsers to make requests across domains. IS NOT SECURITY!! By default WordPress REST API is same-origin only. Set at rest_pre_serve_request hook
  100. 100. Allow All Domains For All Methods add_action( 'rest_api_init', function() { remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' ); add_filter( 'rest_pre_serve_request', function( $value ) { header( 'Access-Control-Allow-Origin: *' ); header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' ); header( 'Access-Control-Allow-Credentials: true' ); return $value; }); }, 15 );
  101. 101. Only Allow GET Requests add_action( 'rest_api_init', function() { remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' ); add_filter( 'rest_pre_serve_request', function( $value ) { $origin = get_http_origin(); if ( $origin ) { header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) ); } header( 'Access-Control-Allow-Origin: ' . esc_url_raw( site_url() ) ); header( 'Access-Control-Allow-Methods: GET' ); return $value; }); }, 15 );
  102. 102. Allows From Certain Origins add_action( 'rest_api_init', function() { remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' ); add_filter( 'rest_pre_serve_request', function( $value ) { $origin = get_http_origin(); if ( $origin && in_array( $origin, array( 'https://hiroy.club' ) ) ) { header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) ); header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' ); header( 'Access-Control-Allow-Credentials: true' ); } return $value; }); }, 15 );
  103. 103. CalderaLabs.org Factories, Storage, UI-Router, and Templates All the things!
  104. 104. AngularJS Factories Factories allow you to create injectable objects. Inject $resource into the factory it to create an object that can automatically handle REST calls. app.factory('Posts',function($resource){ return $resource( ngWP.config.api + ‘/:post_type/:ID?per_page=:per_page’, { post_type: 'posts', ID:'@id', per_page: ngWP.config.posts_per_page, }); })
  105. 105. AngularJS Factories cont’d Posts.get() Posts.query() - like get, but expects array Posts.save() Posts.delete() Posts.remove() Unlike $http these do not return promises
  106. 106. Local Storage https://github.com/grevory/angular-local-storage An AngularJS module that gives you access to the browser’s local storage with cookie fallback. Local storage is a key/value store which we call on. In our example the regular posts (blog) will check for local storage first, before hitting the API.
  107. 107. UI-Router https://github.com/angular-ui/ui-router The Angular-UI project adds modules and functionality to Angular (think WP plugins for WP) State Driven Routing & a lot of other functionality we won’t need. Shows its true power when you have 1 view within another (post.detail within post.list)
  108. 108. Templates Separating out templates into templates directory Cleaner code Separation of views 1 controller can have 1 template 1 template can be powered by multiple controllers Pure HTML (with JSON)
  109. 109. CalderaLabs.org Now Entering The Danger Zone
  110. 110. First thing is first Clone the repo You will need to run npm install and gulp
  111. 111. The config file Create a file called config.js in /assets/js var ngWP = ngWP || {}; ngWP.config = { api: 'https://calderaforms.com/wp-json/', posts_per_page: 5 // Not needed for our menu: 'app' };
  112. 112. Stepping through the code Main APP file UI Router Definitions Small controllers live here Templates Blog/Author List Blog Detail Product List
  113. 113. CalderaLabs.org 5. Plugin Admin Screens With AngularJS The UI Router Making Mini-Apps To Make WordPress Better
  114. 114. Very Similar To Regular NG App
  115. 115. Basic Use add_admin_menu() to print basic HTML Use ui-router to switch routes inside admin page. Use wp_localize_script() for config
  116. 116. Questions? Use PHP or HTML files for templates? How to handle translations? wp_localize_script() PHP templates
  117. 117. Let's Look At Some Code!
  118. 118. What’s Next? Angular 2 Theme currently in development github.com/royboy789/Angular-Wordpress-Theme/tree/v7 Vue.JS - The new simple JS framework ReactJS - What everyone else wants you to learn Admin Theme Boilerplate github.com/WordPress-Admin-JavaScript-Boilerplate/ReactJS-Boilerplate
  119. 119. Want more Roy & Josh teachings? Caldera Learn teaches through 4-week live classroom style webinars. Teachers are Josh and/or Roy with future guest teachers
  120. 120. CalderaLabs.org Josh Pollock JoshPress.net CalderaForms.com CalderaLearn.com CalderaLabs.org @Josh412
  121. 121. CalderaLabs.org Roy Sivan theWPCrowd.com RoySivan.com Lynda.com CaldraLearn.com @royboy789
  122. 122. CalderaLabs.org Want To Learn More? Coming Very Soon CalderaLearn.com

×