The Perfect Mix to Create a Hybrid App: Cordova/Ionic Framework, AngularJS & WordPress
Now that we cleared this up ...
Except two static pages all content you see is coming from the WordPress site via API.
Default Ionic list view, loading the number of posts set in "Reading" in the WP Admin.
Header bar is kept simple. There's only the hamburger (menu) icon, on the right "Search", "Info (leading to the static WordPress pages for this site), plus a Contact form.
There is only the title, post thumbnail and content on it, plus a "Share this" button.
Naturally, typical post meta data like author, date, custom fields and so on, could be included.
For Sharing there's only one Cordova plugin you ever want to use:
https://github.com/EddyVerbruggen/SocialSharing-PhoneGap-Plugin
A basic menu. We've got a separate search page, which gets search results directly from WordPress (in near real-time, a second or so delay).
"Contact Us" features a true contact form being processed on the server.
"Find Us" includes a Google Map.
Besides the "Contact Us" page featuring the contact form this is the only page NOT powered by WordPress data.
Is Ionic Framework the coolest front-end SDK for creating hybrid apps with HTML 5? You'll be the judge!
http://ionicframework.com/
Ionic comes with AngularJS, the popular web application Javascript framework maintained by Google.
https://angularjs.org/
AngularJS services (factories) will get all the data, and controllers put it into shape.
Phonegap by Nitobi was bought by Adobe in 2011.They have an app "Build" Service.
Cordova by Apache is what's underneath Phonegap:
http://cordova.apache.org/
WordPress will bring a REST (JSON) API into core at some point.
http://ionicframework.com/getting-started/
$ npm install -g cordova ionic
$ ionic start myApp sidemenu
$ cd myApp $ ionic platform add ios $ ionic build ios $ ionic emulate ios
Replace ios with android if you build for that platform.
For normal testing in the browser simply run this from your project directory:
$ ionic serve
AngularJS has an excellent service for communicating with HTTP servers:
https://docs.angularjs.org/api/ng/service/$http
angular.module('myApp.services', [])
.factory('MyPostsData', function($http, $q, MyPostsStorage) {
....
}
MyPostsData
Purpose:
Setting the var "data" for holding the incoming data, the JSON URL, the post ID, all stuff that our controller later needs.
MyPostsStorage
Purpose:
Retrieves and stores the posts in JSON, using "angular.fromJSON" and "angular.toJSON"
.factory('MyPostsStorage', function() {
return {
retrieve: function() {
var myPosts = window.localStorage['myposts'];
if(myPosts) {
return angular.fromJson(myPosts);
}
return {};
},
save: function(myPosts) {
window.localStorage['myposts'] = angular.toJson(myPosts);
},
...
JSON returns the number of pages your posts make up in total. This depends on the setting in WP Admin "Reading": "Blog Pages show at most." E.g. if you have 17 posts in total and blog posts to be shown is set at 5, it will read: ""pages":4.
angular.module('myApp.controllers', [])
//Main Posts (Homepage)
.controller('MyPostsCtrl', function($scope, $http, $ionicLoading, MyPostsData,
MypPostsStorage, $timeout) {
...
$scope.loadPosts = function () {
$http({method: 'JSONP', url: MyPostsData.getURL() + 'page=' + $scope.page
+ '&callback=JSON_CALLBACK', timeout: 5000}).
success(function(data) {
...
success(function(data) {
$scope.more = data.pages !== $scope.page;
$scope.posts = $scope.posts.concat(data.posts);
MyPostsData.setData($scope.posts);
MyPostsStorage.save($scope.posts);
$ionicLoading.hide();
}).
error(function() {
$scope.posts = MyPostsStorage.retrieve().posts;
MyPostsData.setData(MyPostsStorage.retrieve().posts);
$ionicLoading.hide();
});
$scope is the glue between factories and controllers
If the user clicks the "Load More" button the next 5 posts are loaded which are appended to the existing posts storage.
Using the JSON API I would need to do the following requests:
Method: get_category_index
Returns an array of active categories.
Method: get_category_posts
Returns an array of posts/pages in a specific category.
Returns a single post object.
Accessing HTML Local Storage only, using nested angular.forEach to retrieve all categories."Push" adds each found category to the array.
.controller('CatsCtrl', function($scope, MyPostsStorage) {
data = MyPostsStorage.retrieve();
$scope.categories = [];
angular.forEach(data, function(post, index){
angular.forEach(post.categories, function(category, index){
$scope.categories.push(category);
});
});
})
<ion-list>
<ion-item ng-repeat="cat in categories | unique: 'slug' | orderBy:'title'" ...>
Returns an array of posts/pages in response to a search query.
Using ionic.debounce() the search is called only every 500ms.
//Search Form
.controller('SearchCtrl', function($ionicLoading, $scope, $http) {
var doSearch = ionic.debounce(function(query) {
var url = 'http://talktechwith.me/api/get_search_results/?search=';
$http({method: 'JSONP', url: url + $scope.query
+ '&post_type=post&callback=JSON_CALLBACK', timeout: 5000}).
success(function(data) {
...
{{$index}} is set to the post id. See "ng-repeat":
https://docs.angularjs.org/api/ng/directive/ngRepeat
<card>
<ion-list>
<ion-item class="item-thumbnail-left" ng-repeat="post in posts
| filter: query" href="#/app/allposts/{{$index}}">
<img ng-src="data:image/jpeg;base64,{{post.custom_fields.base64thumb[0]}}" alt="
{{post.title}}" />
<span class="item-text-wrap" ng-bind-html="post.title"></span>
<i class="icon ion-chevron-right icon-accessory"></i>
<span class="item-text-wrap" ng-bind-html="post.excerpt"></span>
</ion-item>
Thumbnail is in base64 (custom field), then you have "post.title", "post.exercpt".
Date format returning from JSON for this post would be: "2014-04-17 10:37:50".
A custom AngularJS filter takes care of that.
Post thumbnail is cached.
<div class="card">
<div class="item item-text-wrap">
<h1 ng-bind-html="post.title"></h1>
</div>
<div class="item item-text-wrap">
<p ng-bind-html="post.date | customDateFormat"></p>
</div>
<div class="item item-text-wrap single-img">
<img ng-cache ng-src="{{post.thumbnail_images.singlethumb.url}}" alt="" />
</div>
<div class="item item-text-wrap" ng-bind-html="post.content">
</div>
Zero.
All that's left to do is include more content (from custom fields). Look into authentication when doing JSON calls.
Include actual functionality from plugins (e.g. a calendar on the site, and so on) from within the app. Any ideas?
Some were Ionic, some with Cordova plugins. Normally someone already had the issue you had so you find help in the relevant forums. This relates e.g. to implementing Google Maps, Google Analytics etc.
Cordova: What to do when the app user is offline, online? Test push (if needed).
Ionic: Styling, solve some display quirks. Add "pull to refresh perhaps using Ion-Refresher.
AngularJS: Probably do some refactoring.