Flash Sale! Up to 40% off on unlimited courses, tutorials and creative asset downloads Up to 40% off on unlimited assets SAVE NOW
  1. Code
  2. WordPress

Creating Single Page Applications With WordPress and Angular.js

Final product image
What You'll Be Creating

Working with the Angular.js framework is fast and rewarding, and combined with WordPress it can make a really nice SPA (Single-page Application) in a short time-span. With all the CMS controls and plugins WordPress offers, this is a interesting short-cut.

Setting Up the Theme

We will start creating a new theme by using the _tk boilerplate theme to begin with. This is a implementation of the _s underscores theme from Automattic but with Twitter’s Bootstrap implemented.

Grab the theme from GitHub, and place the files in your themes directory:

bash $ cd themes $ wget https://github.com/Themekraft/_tk/archive/master.zip wp-content/themes/$ unzip master.zip Archive: master.zip 69acda231e2a2f8914374df81b89a7aa37d594fa creating: _tk-master/ inflating: _tk-master/404.php inflating: _tk-master/archive.php inflating: _tk-master/comments.php inflating: _tk-master/content-page.php inflating: _tk-master/content-single.php ... ## Rename The Directory $ mv _tk-master/ angular-bootstrap $ rm -f master.zip

Now that we have the _tk starter theme, we will need the npm packages angular and angular-route from inside your theme directory (we are using the name angular-bootstrap).

```bash $ cd wp-angular $ npm init #follow the prompts to create your package.json file … “author”: “”, “license”: “ISC” }

Is this ok? (yes) yes ## Install The Packages $ $ npm install angular angular-route –save ```

  • You must initialize npm within the themes directory with npm init in order to create the package.json, a file which npm uses to manage projects.
  • By using the --save flag in our npm install angular angular-route --save command we are telling npm to add the modules as dependencies to our project.
  • In the future, if we need to share this project with another developer, they will only need to run npm install in the same directory as the package.json in order to get the packages.

Now you will have the packages in your node_modules directory inside your theme. Take a look in the directory and you will be able to see several js files. We will be using angular.min.js for development

Initializing Angular

To include angular.min.js inside WordPress we need to modify the functions.php file so that we can enqueue the scripts in WordPress.

Inside functions.php, find the _tk_scripts() function and append the following to the bottom of the function:

php //Load angular wp_enqueue_script('angularjs', get_template_directory_uri() .'/node_modules/angular/angular.min.js'); wp_enqueue_script('angularjs-route', get_template_directory_uri() .'/node_modules/angular-route/angular-route.min.js'); wp_enqueue_script('scripts', get_stylesheet_directory_uri() . '/js/scripts.js', array( 'angularjs', 'angularjs-route' ));

You will also need to create js/scripts.js—for now just create a blank file.

Now refresh your theme in a browser, and in developer tools you will be able to see angular.min.js included now.

Using Partials

Angular.js has a great system for only updating a partial piece of HTML. To take advantage of this and the angular-route module, we will need to create a directory inside the theme named partials.

bash $ mkdir partials

Inside the partials directory, create a file named main.html for the purpose of testing, and add whatever HTML you like inside.

Localize the Partials Path for WordPress

For Angular to be able to load the partials, we must provide a full URL. I had some trouble using the get_stylesheet_directory_uri() method, but try it for yourself. If it does not work, use your full URL.

Add the following to the _tk_scripts function below where you added the angularjs and angular-route lines from the last step:

php // With get_stylesheet_directory_uri() wp_localize_script('scripts', 'localized', array( 'partials' => get_stylesheet_directory_uri() . '/wp-content/themes/angular-bootstrap/partials/' ) );

If this fails (which at time of writing it was for me), write in the URL, e.g.

php // With hardcoded value wp_localize_script('scripts', 'localized', array( 'partials' => 'https://www.mydomaind.com/wp-content/themes/angular-bootstrap/partials/' ) );

Enabling WP-API

For Angular to work with WordPress, we need to enable the WP-API REST Plugin. This is simple, as it is just the installation of a plugin.

Download and install the plugin from git, and run the following in your plugins dir:

bash git clone git@github.com:WP-API/WP-API.git json-rest-api

Then enable the plugin in your wp-admin panel. You will be able to see JSON output at your-wordpress.com/wp-json once it is enabled.

Building Routes

Routes make up the specific pages of your blog. We can define one for our main.html partial now—and configure it to be shown at the index page of our WordPress.

First ensure the Angular.js app is defined via the ng-app attribute, and in header.php make the following:

```php <!DOCTYPE html>

<html ng-app=”wp”>

``` Here we are calling the app `wp` with the `ng-app` attribute. Also we set the `base` tag so that Angular can find the JSON we have enabled in `WP-API`. Add the following to `js/scripts.js`: ```js angular.module('wp', ['ngRoute']) .config(function($routeProvider, $locationProvider) { $routeProvider .when('/', { templateUrl: localized.partials + 'main.html', controller: 'Main' }) }) .controller('Main', function($scope, $http, $routeParams) { $http.get('wp-json/posts/').success(function(res){ $scope.posts = res; }); }); ``` Now inside `partials/main.html` add this: ```html ``` And finally inside `index.php`, directly after `get_header.php()`, add the Angular attribute `ng-view` on a `div` tag. ```html
``` Refresh the index of your WordPress, and a bullet list of your blog posts will now be displayed on the home page. This is due to the `ng-controller` invoking the `Main` controller from `scripts.js` and the `ng-view` attribute specifying where Angular should render. ### Displaying a Post By Slug Let's add the route now for displaying a WordPress blog via the URL slug. Open `js/scripts.js` and adjust the file so it reads as follows: ```js angular.module('wp', ['ngRoute']) .config(function($routeProvider, $locationProvider) { $routeProvider .when('/', { templateUrl: localized.partials + 'main.html', controller: 'Main' }) .when('/:slug', { templateUrl: localized.partials + 'content.html', controller: 'Content' }) .otherwise({ redirectTo: '/' }); }) .controller('Main', function($scope, $http, $routeParams) { $http.get('wp-json/posts/').success(function(res){ $scope.posts = res; }); }) .controller('Content', ['$scope', '$http', '$routeParams', function($scope, $http, $routeParams) { $http.get('wp-json/posts/?filter[name]=' + $routeParams.slug).success(function(res){ $scope.post = res[0]; }); } ] ); ``` By adding the `Content` controller, we can specify the `$http.get` URI for the JSON posts, and specify the `slug` as the filter parameter. To create this we use the following code: `$http.get('wp-json/posts/?filter[name]=' + $routeParams.slug)`. Note: In order to get the `/:slug` route working, you must specify `/%postname%/` as your permalink structure in the `wp-admin`. Make sure to set the `content.html` with the following: ```html


{{post.content}} ``` Now if you refresh the page, you will be able to navigate to your blog posts via the links in the bullet list you made in the previous step. ## Using Angular Services in WordPress So far we have seen how to create routes and start working with the `wp-json` API. Before we start to write any logic we need a place for it to go, and that is within a Angular `service` (in this example we use a `Factory` service). Create a new file `js/services.js` and add the following code to retrieve categories and posts: ```js function ThemeService($http) { var ThemeService = { categories: [], posts: [], pageTitle: 'Latest Posts:', currentPage: 1, totalPages: 1, currentUser: {} }; //Set the page title in the tag function _setTitle(documentTitle, pageTitle) { document.querySelector('title').innerHTML = documentTitle + ' | AngularJS Demo Theme'; ThemeService.pageTitle = pageTitle; } //Setup pagination function _setArchivePage(posts, page, headers) { ThemeService.posts = posts; ThemeService.currentPage = page; ThemeService.totalPages = headers('X-WP-TotalPages'); } ThemeService.getAllCategories = function() { //If they are already set, don't need to get them again if (ThemeService.categories.length) { return; } //Get the category terms from wp-json return $http.get('wp-json/taxonomies/category/terms').success(function(res){ ThemeService.categories = res; }); }; ThemeService.getPosts = function(page) { return $http.get('wp-json/posts/?page=' + page + '&filter[posts_per_page]=1').success(function(res, status, headers){ ThemeService.posts = res; page = parseInt(page); // Check page variable for sanity if ( isNaN(page) || page > headers('X-WP-TotalPages') ) { _setTitle('Page Not Found', 'Page Not Found'); } else { //Deal with pagination if (page>1) { _setTitle('Posts on Page ' + page, 'Posts on Page ' + page + ':'); } else { _setTitle('Home', 'Latest Posts:'); } _setArchivePage(res,page,headers); } }); }; return ThemeService; } //Finally register the service app.factory('ThemeService', ['$http', ThemeService]); ``` This is a basic factory setup, where we have two internal functions `_setTitle` and `_setArchivePage`. These methods are called from `getPosts` and `getCategories` to update the current page title and also set an internal integer to know which page number we are looking at. We will need to begin using the `ngSanitize` module for parsing inputs to our service. Install this with `npm` as so inside your theme directory: ```bash $ npm install angular-sanitize --save ``` The `ThemeService` is just a basic JavaScript Object which performs a category lookup via `$http.get`, as is the `getPosts` method. We will now make our controller aware of this service. Open `scripts.js` and modify the controller to be aware of `ThemeService`. ```js //Main controller app.controller('Main', ['$scope', '$http', 'ThemeService', function($scope, $http, ThemeService) { //Get Categories from ThemeService ThemeService.getAllCategories(); //Get the first page of posts from ThemeService ThemeService.getPosts(1); $scope.data = ThemeService; }]); ``` Don't forget to enable the `angular-sanitize` module inside your `scripts.js` also on the first line with: ```js var app = angular.module('wp', ['ngRoute', 'ngSanitize']); ``` Finally you will need to ensure the `js/services.js` is enqueued into WordPress as well as the `angular-sanitize` module. Do so by modifying the `functions.php` file and appending the following before the `wp_localize_script` call: ```php wp_enqueue_script('angularjs-sanitize', get_stylesheet_directory_uri() . '/node_modules/angular-sanitize/angular-sanitize.min.js'); wp_enqueue_script('theme-service', get_stylesheet_directory_uri() . '/js/services.js'); ``` Now we will need to update the `main.html` partial to display these categories that are being provided by the ThemeService. ```html <h1>Categories</h1> <ul> <li ng-repeat="category in data.categories"> <span ng-if="current_category_id && category.ID == current_category_id" ng-bind-html="category.name"></span> <a ng-if="!current_category_id || category.ID != current_category_id" href="category/%7B%7Bcategory.slug%7D%7D" ng-bind-html="category.name"></a> </li> </ul> <p>{{data.pageTitle}}</p> <ul> <li ng-repeat="post in data.posts"> <a href="/%7B%7Bpost.slug%7D%7D" ng-bind-html="post.title"></a> <a href="/%7B%7Bpost.slug%7D%7D" ng-if="post.featured_image_thumbnail_url"><img ng-src="{{post.featured_image_thumbnail_url}}" alt="{{post.featured_image.title.rendered}}"></a> <div ng-bind-html="post.excerpt.rendered"></div> </li> </ul> ``` You will now be able to see your posts and categories displayed on your home page via `ng-view` using a `factory` service for Angular. The benefit of this is that all components will have the data available to them. So we can now share the categories object between all of our controllers in our routes. ## Taking Things Further Now that we have a service set up for our theme, we can continue developing the data layer and incorporate Bootstrap styling into the returned HTML. The possibilities now that Angular is configured in your theme are truly endless, and by checking out the repository provided, you will have a quick starting point for creating Angular- and Bootstrap-enabled single-page WordPress applications.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.