Create a Mobile Application Using WordPress, Ionic, and AngularJS [ Part 02 ]

Menu Module

1

2

3

4

lib/

├── menu/

│ └── menu.module.js

│ └── menu.html

The Menu module is very simple. Its purpose is to add a menu inside <ion-side-menu>. Without this module, the side menu would be blank. The menu module declares only a config file, it has ionic and ui.router as dependencies.

01

02

03

04

05

06

07

08

09

10

importmodConfig from './menu.config';

letmod = angular.module('prototype.menu', [

'ionic',

'ui.router'

]);

mod.config(modConfig);

exportdefaultmod = mod.name;

The most interesting part is the configuration. We do not want to create a state for the Menu module as it is available everywhere. Instead, we decorate the root state with the menu content. With the ui-view="menu" being defined in the root state, we need to use menu@root to refer to it.

01

02

03

04

05

06

07

08

09

10

11

12

exportdefaultfunction($stateProvider) {

'ngInject';

$stateProvider.decorator('views', (state, parent) => {

letviews = parent(state);

if(state.name === 'root') {

views['menu@root'] = {

template: require("./menu.html")

};

}

returnviews;

});

}

Home Module

1

2

3

4

5

6

lib/

├── home/

│ └── home.module.js

│ └── home.config.js

│ └── home.controller.js

│ └── home.html

home.module.js

The Home module displays the latests posts of your WordPress website. It has a config file, a controller, and it depends on the following libraries:

ionic

ui.router

wp-api-angularjs

01

02

03

04

05

06

07

08

09

10

11

12

13

importmodConfig from './home.config';

importmodController from './home.controller';

letmod = angular.module('prototype.home', [

'ionic',

'ui.router',

'wp-api-angularjs'

]);

mod.config(modConfig);

mod.controller('HomeController', modController);

exportdefaultmod = mod.name

home.config.js

The config adds a new state, root.home, with the /home URL that has a template and a controller (both living within the module).

01

02

03

04

05

06

07

08

09

10

11

12

exportdefaultfunction($stateProvider) {

'ngInject';

$stateProvider.state('root.home', {

url: "/home",

views: {

'content@root': {

template: require("./home.html"),

controller: "HomeController as homeCtrl"

}

}

});

}

home.controller.js

This is a simplified version of the Home controller logic. It contains two functions:

loadMore: This function populates vm.posts. It uses the $wpApiPostsservice, which is part of the wp-api-angularjs library.

}

functionloadMore() {

return$wpApiPosts.$getList().then((response) => {

$scope.$broadcast('scroll.infiniteScrollComplete');

});

}

}

home.html

The template has a ion-refresher directive that allows users to reload the page by pulling the page down. It also has a ion-infinite-scroll directive that calls the loadMore function when reached. Posts are displayed using the ng-repeat directive.

Tip: Use the track by expression for better performance. It minimizes DOM manipulation when a post is updated.

01

02

03

04

05

06

07

08

09

10

<ion-view>

<ion-nav-title>Home</ion-nav-title>

<ion-content>

<ion-refresherpulling-text="Pull to refresh"on-refresh="homeCtrl.refresh()"></ion-refresher>

</ion-content>

</ion-view>

Post Module

1

2

3

4

5

6

lib/

├── post/

│ └── post.module.js

│ └── post.config.js

│ └── post.controller.js

│ └── post.html

The Post module displays only one post. It has a config file, a controller, and it depends on the same librairies as the Home module.

post.module.js

01

02

03

04

05

06

07

08

09

10

11

12

13

importmodConfig from './post.config';

importmodController from './post.controller';

letmod = angular.module('prototype.post', [

'ionic',

'ui.router',

'wp-api-angularjs'

]);

mod.config(modConfig);

mod.controller('PostController', modController);

exportdefaultmod = mod.name

Similar to the Home module, the config adds a new state, root.post, with the /post/:id URL. It also registers a view and a controller.

post.config.js

01

02

03

04

05

06

07

08

09

10

11

12

exportdefaultfunction($stateProvider) {

'ngInject';

$stateProvider.state('root.post', {

url: "/post/:id",

views: {

'content@root': {

template: require("./post.html"),

controller: "PostController as postCtrl"

}

}

});

}

post.controller.js

The controller retrieves the post specified in the url /post/:id via the $stateParams service (UI router service).

01

02

03

04

05

06

07

08

09

10

11

12

exportdefaultfunction($scope, $log, $wpApiPosts, $stateParams) {

'ngInject';

varvm = this;

vm.post = null;

$scope.$on('$ionicView.loaded', init);

functioninit() {

$wpApiPosts.$get($stateParams.id).then((response) => {

vm.post = response.data;

});

}

}

post.html

The template has a ion-spinner directive that displays a loader while the data is being fetched from the WordPress REST API. When the post is loaded, we use an Ionic card to render the author avatar, the post title, and the post content.

Tip: Use the bindOnce expression, ::, (introduced in Angular 1.3) to avoid watching data that will not change over time.

<h2>{{::postCtrl.post.title}}</h2>

<p ng-bind-html="::postCtrl.post.content"></p>

</div>

</div>

</ion-content>

</ion-view>

Style (Sass)

1

2

3

4

lib/

├── scss/

│ └── _variables.scss

│ └── bootstrap.scss

The bootstrap.scss file that we imported in our entry point is as simple as this:

1

2

@import "./variables";

@import "~ionic-sdk/scss/ionic";

First, we import our variables. We then import the Ionic styles. Importing our variables before Ionic allows us to overwrite whatever Sass variables Ionic has declared.

For example, if you want the positive color to be red instead of blue, you can overwrite it like this:

1

$positive: red!default;

6. Android and iOS

Installation

Run the following commands inside the project folder and chose the platform you want to build for.

1

2

3

4

$ cpconfig.dist.xml config.xml

$ npm run installCordova

Which platforms doyou want to build? (android ios):

In addition to installing platforms within the /platforms folder, the script will install one plugin. For the demo, we need the cordova-plugin-whitelist plugin. It is necessary to allow the application to query the WordPress REST API we created earlier.

If you open config.xml, you will see that we allow access to any kind of origin (<access origin="*" />). Of course, this is only for demo purposes. If you deploy your application to production, then make sure you restrict access like this:

1

Android

Prerequisites

Android SDK

Ant

Running the npm run runAndroid command is a shortcut for rm -rf www/* && webpack && cordova run android. This removes everything within the www folder, dumps a non-minified version of the app in it, and runs the android command. If an Android device is connected (run adb devices to make sure), the command will load the app on the device, otherwise it will use the Android emulator.

1

2

# Run Android

$ npm run runAndroid

iOS

Prerequisites

OS X

Xcode

If you do not have an Apple device, you should install the iOS Simulator. It's really good and better than the Android emulator.

1

$ sudonpm install-g ios-sim

Running npm run runIosEmulator is a shortcut for rm -rf www/* && webpack && cordova run ios. The npm run runIosDevice command is a shortcut for rm -rf www/* && webpack && cordova run ios --device.

1

2

3

# Run iOS

$ npm run runIosEmulator

$ npm run runIosDevice

Conclusion

With this tutorial, I've tried to show you how easy it is to create a hybrid, mobile application for your WordPress website. You should now be able to:

create loosely coupled modules that respect CommonJS specs

import CommonJS modules with ECMAScript 6

use the WordPress REST API client side (with wp-api-angularjs)

leverage Ionic Framework to create a great user interface

use webpack to bundle your application

use Cordova to run the application on iOS and Android

WordPress Hybrid Client

WordPress Hybrid Client (WPHC) is an open-source project available on GitHub that helps you to create iOS and Android versions of your WordPress website for free. WPHC is based on the same technology stack that we used in this tutorial.