3. Definitions
Single Page Application (SPA)
A website with a single page
The most basic SPA consists of an
index.html and bundle of CSS/HTML/JS
files
SPA’s transfer the rendering of content
from the server to the browser
No page refresh: feels like a mobile
app
6. Definitions
WordPress REST API
Proof that WordPress is embracing the
concept of front-end applications
The WP REST API consists of easy-to-use
HTTP endpoints
Allow dynamic population of front-end
applications with any WordPress data
Fastest way to access WordPress data in
JSON format
7. Definitions
WordPress REST API
The WP REST API can be extended to:
Modify responses
Create internal classes
Add endpoints
Access custom post types/taxonomies
So much more…
var source = "developer.wordpress.org/rest-api"
8. Why Single Page Applications?
Advantages
Incredibly lightweight
Rapid deployment
Extremely modular
Built in mock testing
9. Why Single Page Applications?
Challenges
Not suited for games, GUI editors, or
non-standard DOM manipulation
Initial load time
Extra effort required for SEO
10. Why Single Page Applications?
SPA’s are how sites of the future will
be built. It’s already happening:
var source = "madewithangular.com"
11. Building a SPA Theme for
WordPress
Creating a WordPress theme for the SPA
Understanding AngularJS SPA components
Building an AngularJS SPA
Leveraging the WP REST API
12. Creating a WordPress theme for the
SPA
Folder structure
root/
includes
assets/
app…
img
lib/
css
js
13. Creating a WordPress theme for the
SPA
File structure
root/
footer.php
functions.php
header.php
index.php
style.css
14. Creating a WordPress theme for the
SPA
File structure
root/includes/
enqueue.php
15. Creating a WordPress theme for the
SPA
File structure
root/assets/lib/css/
bootstrap.min.css
sizer.css
16. Creating a WordPress theme for the
SPA
File structure
root/assets/lib/js/
angular.min.js
angular-sanitize.min.js
bootstrap.min.js
jquery.min.js
ui-route.min.js
17. Creating a WordPress theme for the
SPA
functions.php
<?php
/*
* Author: Kenneth Schnetz, VendorFuel
* URL:vendorfuel.com/spa-theme
* Custom functions, support, custom post types and more.
*/
require_once 'includes/enqueue.php’;
add_filter('redirect_canonical', 'no_redirect');
function no_redirect () {
return false;
}
?>
24. Creating a WordPress theme for the
SPA
enqueue.php
//app scripts: ctrl–controller, dir-directive, fac–factory, fil-filter,
svc-service
wp_enqueue_script( 'app', get_template_directory_uri() . '/assets/app/app.js’);
wp_enqueue_script( 'app-config', get_template_directory_uri() . '/assets/app/config.js’);
wp_enqueue_script( 'app-run', get_template_directory_uri() . '/assets/app/run.js’);
wp_enqueue_script( 'fac-intc', get_template_directory_uri() . '/assets/app/factories/interceptor.js’);
wp_enqueue_script( 'svc-post', get_template_directory_uri() . '/assets/app/services/post.js’);
wp_enqueue_script( 'svc-page', get_template_directory_uri() . '/assets/app/services/page.js’);
wp_enqueue_script( 'dir-resize', get_template_directory_uri() . '/assets/app/directives/resize.js’);
wp_enqueue_script( 'ctrl-header', get_template_directory_uri() . '/assets/app/controllers/header.js’);
wp_enqueue_script( 'ctrl-home', get_template_directory_uri() . '/assets/app/controllers/home.js’);
wp_enqueue_script( 'ctrl-contact', get_template_directory_uri() . '/assets/app/controllers/contact.js’);
wp_enqueue_script( 'ctrl-post', get_template_directory_uri() . '/assets/app/controllers/post.js’);
wp_enqueue_script( 'ctrl-footer', get_template_directory_uri() . '/assets/app/controllers/footer.js’);
//NOTE: these should all be concatenated, minified, and enqueued as one
file in production
25. Creating a WordPress theme for the
SPA
enqueue.php
//styles
wp_enqueue_style( 'bootstrap', get_template_directory_uri() .
'/assets/lib/css/bootstrap.min.css’);
wp_enqueue_style( 'sizer', get_template_directory_uri() .
'/assets/lib/css/sizer.css’);
wp_enqueue_style( 'styles', get_template_directory_uri() . '/style.css');
26. Creating a WordPress theme for the
SPA
enqueue.php
//WordPress variables to be used in SPA
wp_localize_script('app', 'localized', array(
'dir' => array(
'url' => get_home_url(),
'root' => get_template_directory_uri(),
'templates' => get_template_directory_uri() .
'/assets/app/templates/'
),
'nonce' => wp_create_nonce( 'wp_rest' )
)
);
}
?>
27. Building an AngularJS SPA
Understanding the components
View: a rendered state of the application
State: different parts or “pages” of the site
Template: HTML file associated with a
specific view
Model: the data associated with the
application
Scope: context where the model is stored and
accessed
Controller: main logic behind each specific
view
28. Building an AngularJS SPA
Understanding the components
Expression: code snippets in HTML to access
scope data
Directive: HTML extensions with custom
attributes and elements
Filter: formats the value of an expression
Factory/Service: reusable logic accessible to
all controllers
Module: container for the different parts of
the app
29. Building an AngularJS SPA
Folder structure
root/assets/app/
controllers
directives
factories
filters
services
templates
53. Building an AngularJS SPA
Directives
Extended HTML attributes with the ng- prefix
Many built in directives
ng-app
ng-model
ng-bind
etc…
You can define your own directives
Resize: get current screen width in
relation to bootstrap columns (xs, sm, md,
lg)
54. Building an AngularJS SPA
Directives - resize
admin_js_app.app.directive('resize', function($window) {
return function($scope) {
GetSizing();
angular.element($window).bind('resize', function() {
$scope.$apply(function() {
GetSizing();
});
});
function GetSizing() {
$scope.width = $window.innerWidth;
CheckSizing($scope.width);
};
function CheckSizing(w) {
if (w < 768) { SetBools(true); }
else if ((w >= 768) && (w < 992)) { SetBools(false, true); }
else if ((w >= 992) && (w < 1200)) { SetBools(false, false, true);}
else { SetBools(false, false, false, true); }
};
function SetBools(xs = false, sm = false, md = false, lg = false) {
$scope.isXS = xs; $scope.isSM = sm; $scope.isMD = md; $scope.isLG = lg;
};
};
});
55. Building an AngularJS SPA
Factories
Global functionality provided to the
controllers
Provides modularized global
functionality
You can define your own factories
Interceptor: modify HTTP requests and
responses
57. Building an AngularJS SPA
Services
Similar to factories
Provides modularized global functionality
Many built in services:
$http
$location
$timeout
etc…
You can define your own services
Leveraging the WP REST API is a perfect use case
58. Leveraging the WP REST API
Provides API endpoints for WordPress
data types
Sends and receives JSON objects
Extremely simple to use
NOTE: you will need a localized nonce
to utilize the WP REST API fully from a
SPA
59. Leveraging the WP REST API
Use case examples
yoursite.com/wp-json/v2/
pages
pages?slug=spa-contact
posts
posts?id=1
Will not have linked data
posts?_embed&id=1
Will have linked data
60. Leveraging the WP REST API
Page
Page with a contact form via shortcode
Page service
Page controller
Page template
61. Leveraging the WP REST API
Page - content
WordPress page content in this example:
<h3 style="text-align: center;">
Please fill out your contact info and we will get back to you
shortly!
</h3>
<div style="text-align: center;">
[contact-form-7 id="5" title="Contact form 1"]
</div>
62. Leveraging the WP REST API
Page - service
admin_js_app.app.service('Page', function($rootScope, $http, $sce) {
this.GetSlug = function (slug) {
var req = { method: 'GET', url: localized.dir.url + '/wp-
json/wp/v2/pages?slug=' + slug };
var promise = $http(req).then(function(resp){
var page = {};
if (resp.data[0]) {
page.id = resp.data[0].id;
page.title = $sce.trustAsHtml(resp.data[0].title.rendered);
page.content = $sce.trustAsHtml(resp.data[0].content.rendered);
} else { page.error = "Page not found"; }
return page;
}, function(resp){ return resp; });
return promise;
}
});