CBPWordPress – Display content from your WordPress blog in an iOS app

CBPWordPress is an iOS library that will allow you to easily include content from a WordPress blog. The library can fetch lists of posts, individual posts and submit comments.

It is, of course, available on GitHub under the MIT License as well as via CocoaPods.

Background

Over the last few years, I’ve built an maintained the accompanying iOS app for Broadsheet.ie. It’s nearly tradition now for me to release a new version every year

The Example App

Included in the repo is an example app that is the basis for the new Broadsheet.ie app. This app will allow you to browse the site content, search for posts and submit comments.

The app also refreshes itself in the background, reminds the user of its existence in the morning and evenings and updates the logo on the home screen every 6 hours.

The full app includes Google Analytics and Mobile Ad SDK, Crashlytics and Conveser.io and has its own fork.

Installing the Plugin

Before you can use CBPWordPress, you must install the WP-JSON-API plugin to provide the data to the app. This is a slightly modified fork that provides a few extra fields to make things a bit smoother for the app.

If you want to be able to submit comments via the app, remember to turn on the Respond controller in the JSON API settings section.

Getting Started With The Example

Check out the repo from GitHub and initialise the Example pods:

git clone https://github.com/kmonaghan/CBPWordPress.git
cd CBPWordPress/Example
pod install

If you open the example project workspace and build and run the app, it should pull the latest 10 posts from Broadsheet.ie.

Using CBPWordPress In Your Own App

CocoaPods

The easiest way to use CBPWordPress is to install it via CocoaPods. To do that, just add the following line to your Podfile and then run ‘pod update’.

pod 'CBPWordPress'

Add the CBPWordPress project to your project

If you don’t use CocoaPods, add all the files in the CBPWordPress folder to your project. Then simply include the CBPWordPress.h header file where you want to use the library.

Note that you will also have to include AFNetworking in your project.

Usage

Pointing the library at your own WordPress installation is trivial. The first call to the library should be to set the root URL for the API.

[CBPWordPressAPIClient rootURI:@"http://YOUR-API-URL];

Once that is set, the calls to the API will use that URL.

Fetching A List Of Posts

To get a list of posts, you use the fetchPostsWithParams:withBlock: method from the NSURLSessionDataTask category.

In the example below, the first page of the recent posts is retrieved and the posts assigned to an array.

__weak typeof(self) weakSelf = self;

[NSURLSessionDataTask fetchPostsWithParams:@{@"page": @(1)}
withBlock:^(CBPWordPressPostsContainer *data, NSError *error) {
if (error) {
//Handle Error
return;
}

__strong typeof(weakSelf) strongSelf = weakSelf;

strongSelf.posts = data.posts;
}];

The allowed parameters are:

  • page: The page you want to fetch. Starts at 1.
  • count: The number of posts to retrieve. Defaults to 10.

Fetching A Post

If you know the post id, you can fetch a post using the fetchPostWithId:withBlock: method from the NSURLSessionDataTask category. The example below fetches post 1234 and assigns it to a local post variable.


__weak typeof(self) weakSelf = self;

[NSURLSessionDataTask fetchPostWithId:1234
withBlock:^(CBPWordPressPost *post, NSError *error){
if (error) {
//Handle Error
return;
}

__strong typeof(weakSelf) strongSelf = weakSelf;

strongSelf.post = post;
}];

If you have the URL of the post, you can use the fetchPostWithURL:withBlock: method instead. You pass the full URL of the post as the parameter.

Comment On A Post

To comment on a post, the postComment:withBlock: method from the NSURLSessionDataTask category is used. The method takes a CBPWordPressComment object as the first parameter. Below is an example comment being initialised.

CBPWordPressComment *newComment = [CBPWordPressComment new];
newComment.postId = 1234;
newComment.email = @"example@example.com";
newComment.name = @"Jonny Appleseed";
newComment.content = @"This is a comment!";
//Optional
newComment.url = @"http://somewebsite.com";
//If the comment is replying to another comment
newComment.parent = 1234;

Note that the URL and parent properties are optional but everything else is required. The parent property should be only be set if the user is replying to a comment and should be that comment’s id.

Once the comment is initialised, pass it to the postComment:withBlock: method. In the following example, the new comment is submitted and on success is set to the returned comment object.

__weak typeof(self) weakSelf = self;

[NSURLSessionDataTask postComment:newComment
withBlock:^(CBPWordPressComment *comment, NSError *error){
__strong typeof(weakSelf) strongSelf = weakSelf;

if (error) {
//Handle error
return;
}

strongSelf.comment = newComment;

Known issue: if WordPress detects a duplicate comment, the resulting return is HTML rather than JSON.

To Do

The library is very much a work in progress. Some of the planned functionality to add is:

  • Add option to fetch data from WP-API plugin
  • Implement helper methods for each WP-JSON-API endpoint (get_category_posts, get_tag_posts etc.)
  • Add a Today Extension to the example app

Contributing

Contributions via pull requests and suggestions are also welcome (although no promises that anything will be added).

If you do use this for your own app, I’d love to hear from you.

Creating an iOS Framework and Today Extension

One of the exciting new things announced at the WWDC keynote this month was App Extensions. This really opens up inter-app communication as well as letting developers do interesting things with the notification center and sharing.

I’m convinced that pretty much every news organisation is going have a widget included in their app to show the latest couple of stories. To that end, I’m going show here how I added a Today widget to a simplified version of the Broadsheet app.

All the code talked about here is available on GitHub under the MIT license.

Caveats:

  • This all works in the simulator but has not been tested on a device yet  Kindly tested by Liam Dunne and it works (phew!)
  • Some of the cell layouts are a bit off but are good enough for informational purposes
  • This is still all in Obj-C rather than being all cool and done in Swift

Starting off

Our starting point is a simple app that grabs the JSON feed of the latest 10 posts Broadsheet.ie and displays them in a UITableView. Tapping on a cell brings you to a screen that displays the content of the post in a UITextView (this will sometimes be mangled due to the content).

To this app we’re going to add a Today widget that displays the latest two post and brings you back to the app when a cell is tapped.

The base app is in the (imaginatively called) ‘baseapp‘ branch.

Creating The Framework

First, we’re going to create a framework to hold the common files that will be used by both the app and the widget. We need to add a framework target to the project by doing the following:

  • Select the project
  • Editor->Add Target
  • Select ‘Framework & Library’
  • Select ‘Cocoa Touch Framework’ and hit ‘Next’
  • Give it a name (ours is called CBPKit) and hit ‘Finish’

The framework should be automatically included in your app target (check under ‘Link Binary With Libraries’ in ‘Build Phases’).

Move any files you want your framework to provide from your app to the framework (note that this doesn’t move the files on disk). In this case it is everything but the view controllers.

Select the headers and in the ‘Utilities’ pane select your framework and set the option on the right to ‘project’.

Select the implementation files and again in the ‘Utilities’ pane select your framework and unselect your project.

For displaying the images in the cells, I’m using SDWebImage. I could have just add the relevant SDWebImage files to the framework I just created, but this seems wrong to me as:

  • You may include another framework in the future that includes and exposes SDWebImage and then you’d have a clash
  • You release your framework and someone can’t use it because your included version of SDWebImage clashes with the version they want to use
  • SDWebImage may release its own framework in the future

Instead, I created a separate framework (with the exact same steps as above) called SDWebImageKit.

As I may want to use this framework in another project, I set the headers to ‘Public’ in the ‘Utilities’ pane and added each of the headers to the framework header file. This means that I can import all the headers at once using:

#import <SDWebImageKit/SDWebImageKit.h>

When you run the app now, it should look no different to before despite the internal changes.

If you switch to the ‘framework‘ branch, you’ll see this built on top of the previous branch.

Today Extension

Like the framework, we first add a Extension target to the project.

  • Select the project
  • Editor->Add Target
  • Select ‘Application Extension’
  • Select ‘Today Extension’ and hit ‘Next’
  • Put in a name (ours is called CBPTodayExtensionExample) and hit ‘Next’
  • Go into Build Phases and include both the frameworks from above in the ‘Link Binary With Libraries’

If you run the project now in the simulator and pull down the notifications drawer, you should see ‘1 New Widget Available’ at the very bottom. Tapping on ‘Edit’ will bring up all the available widgets and the new widget should be at the bottom with a green plus beside it. Tap the plus and it should be displayed with any other active widgets when you hit ‘Done’.

‘Hello world’ is a nice greeting but we want to replace this with a table containing 2 tappable cells containing the latest two posts from Broadsheet.

I don’t use storyboards, so I removed the default one added by the template. In info.plist I removed the key NSExtensionMainStoryboard and replaced it with NSExtensionPrincipalClass and put ‘TodayViewController’ as the value.

The cell I use in the app is a bit big for displaying in the notification center, so I added a set of new constraints to display a more compact cell. This means I can reuse the same data source and cell from the main app in my Today extension with just some minor modifications.

In the TodayViewController, there are two places that need to load data from the network – when the widget is created and when widgetPerformUpdateWithCompletionHandler is called. For the former, I load posts in viewDidLoad, so that they should be ready by the time the widget displays. When iOS thinks the widget will be displayed to the user after it has been first displayed, widgetPerformUpdateWithCompletionHandler is called giving the widget a chance to update the posts displayed.

In this example, both cells are always reloaded even if they already contain the posts returned. It probably shouldn’t do this and instead only replace the updated cells, but that’s a bit of extra polish I’ll leave for when building the full widget.

To get the app to open when a cell is tapped, a custom URL scheme is registered in the base app and this can be called using the UIViewController’s extensionContext to open the URL.

If you switch to the ‘todayextension‘ branch, you’ll see this built on top of the framework branch.

Finally

To keep everything tidy (and to satisfy my developer OCD), I used Synx to synchronise the files and folders to match those used in the project.

That’s all that’s needed to get a Today widget up and running. I’m delighted it’s so straight forward and I’m looking forward to seeing what people do with them.

Aside

There’s an issue with the debugger in Xcode attaching to the extension process properly. You can manually attach it by selecting ‘Debug’->’Attach to Process’ and finding the extension process under ‘System’. If your extension crashes on startup you won’t be able to this.

If you want to see logging from before you reattached the debugger, you can view it in the system log. You can open it from ‘Debug’->’Open System Log…’. If you filter it by your extension’s bundle id you’ll get the relevant entries.

Update 18/6/2014: In the release notes for Xcode 6 Beta 2 there’s a list of issues around the debugger and extensions. One pertinent to this app is that you can’t debug a today widget in the simulator but you can on device.

Update 7/7/2014: Xcode 6 Beta 3 came out today and fixes some of the debugging issues.

Recommended Reading and Viewing

An Experiment In iOS App Pricing

I’ve a couple of paid apps and I am never really sure what to price them. On the one hand it’d be nice if I made anything from them but I also want people to actually use them. Last year, Michael Jurewitz wrote a series of fascinating posts on App Store Pricing. In particular the section on price elasticity stuck in my head.

My tax calculator app (unimaginatively called) TaxCalc.ie generally does best at two times of the year – in and around the budget announcements and in January (presumably as people are checking their first payslip).

On the run up to the 2014 Budget, I did a bigger than normal update to the app both modernising its internals and sprucing up the UI a bit. Based on the extra effort that was put in and keeping price elasticity in mind, I decided to increase the price on the 1st of October from 89c to €1.79 as a bit of an anti-sale.

For the period between the 1st of October 2013 and the 6th of January 2014 (€348.80 profit), I sold 320 copies compared to 315 the previous year (€151.20 profit). So not only did I sell more, I also more than doubled my profit.

I hadn’t really noticed this until I was doing my usual end of year comparisons at the start of January. As people seemed to be as willing to pay €1.79 as they were 89c, I decided to ratchet up the price to the next tier (€2.69) for the rest of January. The result was 72 sales compared to 101 in the same period of 2013. It may have been a 30% drop in downloads, but when you look at the proceeds, the app still generated more than twice amount at €118.08 as opposed to €54.54. I’d call that a successful experiment.

Will I increase the price again? Possibly for a week later in the year, but probably not. My gut feeling is that another price increase would would further drop download numbers to the point where it would make less money. More likely, I’ll either release the 2015 calculator as a standalone app or offer an update as an in-app purchase.

The tax calculator is a very niche app and and it’s really only providing me with beer money. Still, it was well worth tweaking the price to squeeze that little bit extra out of it to make the time spent developing it actually worth something.

tl;dr Increased the price of TaxCalc.ie from 89c to €1.79 and finally to €2.69 resulting in 2x profits while more or less maintaining the number downloads.

Slides from the talk “Face Detection and Recognition for Fun and Profit” for XCake

These are the slides to my talk for XCake on using OpenCV for face recognition on iOS. It should be noted that the first half of the talk deals with using OpenCV to also detect faces and so applies to any platform you can use OpenCV on. The simplified code sample on slide 14 should more or less work for you on non-iOS implementations.

Links

Slide 4: https://en.wikipedia.org/wiki/Prosopagnosia

Slide 6: http://opencv.org/

Slide 9: http://coding-robin.de/2013/07/22/train-your-own-opencv-haar-classifier.html

Slide 10: http://docs.opencv.org/modules/contrib/doc/facerec/facerec_tutorial.html

Slide 25: http://www.rekognition.com/
https://www.bioid.com/solutions/solutions-by-application/bioid-for-facedotcom.html
http://api.animetrics.com
http://www.identitykit.it/
http://www.skybiometry.com/

Slide 27: https://github.com/kmonaghan/FaceRecognition

Other

520 – What’s New in Camera Capture from WWDC 2012 talks about CIDetector and AVCaptureMetadataOutput from about the 19 minute mark. You should look at the sample code from that talk (StacheCam) for details on how to implement CIDetector and AVCaptureMedataOutput rather than the SquareCam project referenced in the Apple Documentation.

iOS 6, Auto Layout and MKMapView

I’m currently in the throws of updating an app for iOS 7. As part of the update, I’m throwing out all the XIBs and buying fully into using auto layout programatically.

I’ve been concentrating on getting it all to work on iOS 7 and only started at looking at how it looks on iOS 6 this week. Straight away I hit an issue

Auto Layout still required after executing -layoutSubviews. MKMapView's implementation of -layoutSubviews needs to call super.

The solution turns out to fairly straight forward. You don’t seem to be able to directly apply constraints between a MKMapView and another subview under iOS 6. Instead, you place your map into a container view and set the autoresizingMask to flexible width and height. You can then apply any constraints needed to the container view.

The code below simply creates a MKMapView which takes up the whole screen. From there, you could add buttons to the container view that are constrained to float 30 points from the bottom (which is what I needed to do).

self.mapContainerView = [[UIView alloc] initWithFrame:CGRectZero];
self.mapContainerView.translatesAutoresizingMaskIntoConstraints = NO;

self.mapView = [[MKMapView alloc] initWithFrame:self.mapContainerView.frame];
self.mapView.showsUserLocation = YES;
self.mapView.delegate = self;
self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.mapContainerView addSubview:self.mapView];

[self.view addSubview:self.mapContainerView];

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_mapContainerView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_mapContainerView)]];

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_mapContainerView]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_mapContainerView)]];

As an aside: Reveal has been invaluable in debugging my auto layout issues.

TTWordPress – a Three20 library to display a WordPress blog in an iOS app

DEPRECIATED use KMWordPress instead.
DEPRECIATED use CBPWordPress instead.

TTWordPress is a library I wrote to easily display a WordPress blog in an iOS app.  I originally wrote it for the Visionary.ie app and was then able to expand on that to create the Broadsheet.ie app.  Since I found it useful, I thought I’d release it into the wild and see what happens.

To provide the data from a WordPress blog is a nice machine readable format, the excellent JSON API plugin is used.  Obviously, it needs to be installed for the iOS to be able to retrieve anything but that’s a trivial matter.  If you want users to be able to comment on posts, you need to activate the ‘Respond’ controller in the API settings.  On the iOS side of things, the library uses Three20 for the consuming the JSON and displaying the information in tables.

To use the library in your own app, you first need to add Three20 to your project (if you’re not already using it).  Open the example TTWordPress project and copy the WordPress folder and all its contents to your project.

To point the library at your own blog, you need to edit the following line in TTWordPress.h:


#define WP_BASE_URL @"http://ttwordpress.karlmonaghan.com/"

In this file, you can also change the default title for the latest posts view and the way dates are displayed for posts and comments.

Then in your AppDelegate, add the following includes:

#import "WordPressBlogViewController.h"
#import "WordPressAddCommentViewController.h"

Then add the following lines:

[map from:@"tt://examplepostlist" toSharedViewController:[WordPressBlogViewController class]];
[map from:@"tt://blog/author/(initWithAuthorId:)" toViewController:[WordPressBlogViewController class]];
[map from:@"tt://blog/category/(initWithCategoryId:)" toViewController:[WordPressBlogViewController class]];
[map from:@"tt://blog/post/comment/(initWithPostId:)" toModalViewController:[WordPressAddCommentViewController class]];

The first line sets the path to a view controller that will list the latest posts from your blog, the second shows the posts belong to a particular author, the third from a particular category and the fourth is the modal pop up for making a comment.  The assumption here is that the list of posts from your blog will be a tab in your app hence being a shared view controller as opposed to the other two which are created and destroyed on demand.

The final step is to call the latest post view controller from somewhere.  In the sample project, it’s added to the UITabViewController. Once you’ve done that, compile and run your app and you should see your blog posts.

The code is available via a Git repo at https://github.com/kmonaghan/TTWordPress.

If you do use it, I’d love to hear from you.

The icon used is from the excellent Glyphish set.

DEPRECIATED use KMWordPress instead.