Cloud Four Blog

Technical notes, War stories and anecdotes

iPhone App Store Blinders

What happens when you are so enamored with iPhone apps that you forget about the rest of your mobile strategy? Chanel’s iPhone App is what happens.

Chanel was one of the early innovators in using the iPhone App Store as a marketing vehicle. They launched their iPhone application in August 2008.

Chanel's iPhone application

The application provides the following a decent set of features. Nothing earth shattering, but they make sense for what Chanel would like to accomplish.

So what’s to complain about? Try finding the application on your phone.

Assume for a second that you don’t know that the application exists. So you’re really not looking for an application. You’re simply trying to find a local store.

You open Google in Mobile Safari and search for “Chanel.”

None of the results mention the iPhone App, but that’s ok because the top result is Chanel.com. Surely you can find what you are looking for there.

Screen shot of Chanel.com home page on iPhone. Empty page with broken icon due to the fact the entire page is in Flash.

On your iPhone, Chanel.com is an empty page with a icon indicating a broken media file. The whole page is written in Flash which doesn’t work on the iPhone.

Not only can you not find any information about Chanel including where the local store might be, but you won’t even find a link to the iPhone application that they spent thousands of dollars developing.

I wish I could say this was uncommon. Unfortunately, this is typical of the mindset of American businesses when it comes to mobile. Everyone wants an iPhone application. Business logic be damned.

What good is it to have an iPhone application if no one can find it? Shouldn’t anyone be able to find your store from their mobile web browser regardless of whether they have your app or even have an iPhone?

I love my iPhone, but an iPhone app does not constitute a mobile strategy.

WordPress: Taking the Hack out of Multiple Custom Loops

[toc title="Custom Loop Hacking: Contents"]

Overview

Consider this a looking-forward-to WordCamp Portland post! WordCamp is this weekend in Portland, Sept. 19-20. It is utterly sold out!

This post is aimed at those comfortable with WordPress hackery and PHP programming.

Making things work for our customers often–nay, all the time–ends up with the need for multiple WordPress loops on pages

On a given day, one of our enterprise or otherwise-crafty-and-complex clients may request, say, the three most recent posts about foo in the right sidebar, “upcoming events” (e.g. date-sensitive posts in some events category) in another box, a couple of embedded and editable WordPress page components, a random post or two, and then the “traditional” post loop itself. Whew.

I have long tried to find the best way to handle custom loops. For sake of definition, custom loop here means querying and displaying posts and/or pages within a page that are not that page’s “natural” queried posts (that is, the landing page of a WordPress blog by default “naturally” queries the most recent posts, and a category page “naturally” queries for posts in a given category).

There are a number of plugins and even entire themes keyed toward custom-loop-heavy development and modular formatting of posts in loops, including the Carrington JAM theme. But I find that most solutions either are a bit too baked–the Carrington theme feels like it would require a lifestyle change and an adoption of a new outlook (not that I’m ragging on the Carrington stuff; I’ve actually heard good stuff about it)–or a little bit too under-baked and soggy in the middle (“Here’s a two-line code snippet to call query_posts! I think? I mean, this should work, probably.”).

I’m Tired of Solving these things Ad Nauseum

Problems I keep running into:

  • The dreadful tendency to forget to restore the “natural”, appropriate global post and wp_query objects after one is done messing about. Those are sort of inviolate and should not be sullied, but it’s wretchedly easy to lose track.
  • Yet, if one does not pollute the global namespace with posts in the custom loop, one cannot access certain template tags and the like.
  • The mishmash of logic and formatting that often happens when one munges together a custom query in a page or post template is totally aesthetically unpleasing and betrays a certain lack of character/mettle.
  • Duplicated markup across a site that would better be modular and re-used.

It occurred to me recently that there is a straightforward way to deal with this. By creating a custom function (in a given theme’s functions.php file) of relatively low complexity, one can solve some of these problems once and for all.

The function: lyzadotcom_custom_loop($args)

It’s prefaced with lyzadotcom because I initially wrote it for my own site, but you can call it whatever.

This is what it looks like, and we’ll talk about it more below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
 * To use when a loop is needed in a page. Use $args to call query_posts and then
 * use the template indicated to render the posts. The template gets included once
 * per post.
 *
 * @param Array $args               Wordpress-style arguments; passed on to query_posts
 *                                  'template' => name of post template to use for posts
 * @return Array of WP $post objs   Matching posts, if you should need them.
 */
function lyzadotcom_custom_loop($args)
{
    global $wp_query;
    global $post;
    $post_template_dir          = 'post_templates';
    /* The 'template' element should be the name of the PHP template file
       to use for rendering the matching posts. It should be the name of file,
       without path and without '.php' extension. e.g. the default value 'default'
       is $post_template_dir/default.php
    */
    $defaults                   = Array('template' => 'default' );
 
    $opts = wp_parse_args($args, $defaults);
 
    // Bring arguments into local scope, vars prefixed with $loop_
    extract($opts, EXTR_PREFIX_ALL, 'loop');
 
    // Preserve the current query object and the current global post before messing around.
    $temp_query = clone $wp_query;
    $temp_post  = clone $post;
 
    $template_path = sprintf('%s/%s/%s.php', dirname(__FILE__), $post_template_dir, $loop_template);
 
    if(!file_exists($template_path))
    {
        printf ('<p class="error">Sorry, the template you are trying to use ("%s")
            in %s() does not exist (%s).',
            $template,
            __FUNCTION__,
            __FILE__);
        return false;
    }
    /* Allow for display of posts in order passed in post__in array
       [as the 'orderby' arg doesn't seem to work consistently without giving it some help]
       If 'post__in' is in args and 'orderby' is set to 'none', just grab those posts,
       in the order provided in the 'post__in' array.
    */
    if($loop_orderby && $loop_orderby == 'none' && $loop_post__in)
    {
        foreach($loop_post__in as $post_id)
            $loop_posts[] = get_post($post_id);
    }
    else
        $loop_posts = query_posts($args);
 
    /* Utility vars for the loop; in scope in included template */
    $loop_count             = 0;
    $loop_odd               = false;
    $loop_even              = false;
    $loop_first             = true;
    $loop_last              = false;
    $loop_css_class         = '';                               // For convenience
    $loop_size = sizeof($loop_posts);
    $loop_owner = $temp_post;       /* The context from within this loop is called
                                       the global $post before we query */
 
    foreach($loop_posts as $post)
    {
        $loop_count += 1;
        ($loop_count % 2 == 0) ? $loop_even = true : $loop_even = false;
        ($loop_count % 2 == 1) ? $loop_odd  = true : $loop_odd  = false;
        ($loop_count == 1) ?     $loop_first = true : $loop_first = false;
        ($loop_count == $loop_size) ? $loop_last = true : $loop_last = false;
        ($loop_even) ? $loop_css_class = 'even' : $loop_class = 'odd';
        setup_postdata($post);
        include($template_path);
    }
    $wp_query = clone $temp_query;  // Put the displaced query and post back into global scope
    $post = clone $temp_post;       // And set up the post for use.
    setup_postdata($post);
    return $loop_posts;
}

Loop Templates

  • By default, this function will look for loop templates in a directory called ‘post_templates’ in your theme’s template directory. Also by default, it will look for a file called ‘default.php’ in this directory. You can change the directory for templates if this bugs you.
  • Templates are PHP files and you can do what you will in them. All template tags are available.
  • You can create as many template files as you want and use them for different chunks of content.

Example Loop Template File

For example, this might be your default.php template file.

    <div class="post <?php echo $loop_css_class ?>" id="post-<?php the_ID(); ?>">
        <h4><?php echo $loop_count; ?><a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>">
            <?php the_title(); ?>
        </a></h4>
        <em><?php the_date(); ?></em><br />
        <?php the_excerpt(); ?>
    </div>

You can see that, in addition to standard “>WordPress template tags, I’ve used a couple of the batching variables made available by the function.

Batching Variables Available to Loop Templates

Available variables in loop templates are:

$loop_count                         // The count of the current post within the loop
$loop_odd                           // True if we're on an odd item (e.g. $loop_count = 1, 3, 5...)
$loop_even                          // True if we're on an even item (e.g. $loop_count = 2, 4, 6...)
$loop_first                         // True if this is the first post/page in the loop
$loop_last                          // True if this is the last post/page in the loop
$loop_css_class                     // 'even' if $loop_even, 'odd' if $loop_odd
$loop_size = sizeof($loop_posts);   // Total number of posts/pages in loop
$loop_owner = $temp_post;           // The post in global scope before this loop was entered

How to Use this Thing

Requirements

  • The use of clone means you need to have PHP5.
  • I have not tested this on any versions of WordPress 2.8. I imagine it would be OK, but YMMV.

Usage

  1. Edit your themes functions.php file and stick this function in it.
  2. Create at least one loop template file. By default (unless you tell it otherwise, which likely you will) this function looks for a template in
    <template_directory>/post_templates/default.php

    We’ll talk about templates shortly.

  3. Call the function from any WordPress template file you might need it from. You talk to it with WordPress query-string-style arguments. This function takes any argument that the query_posts() function takes.
  4. It also takes an additional argument, ‘template’. This is how you tell it which loop template to use.

Usage Examples

Embed an editable Page into Content

  1. In the desired WordPress template:
        <?php
            $args = Array('pagename'         => 'embed-this-page',
                          'template'         => 'embed');
        ?>
        <?php lyzadotcom_custom_loop($args); ?>
  2. This is going to look for the template ‘embed.php’ in your $post_templates directory. This template might look like this:
        <div class="embedded" id="embedded-page-<?php the_ID(); ?>">
            <strong><?php the_title(); ?></strong><br />
            <?php the_content(); ?>
            <?php edit_post_link(); ?>
        </div>

Display 5 Most Recent Posts from Several Categories, Titles Only

  1. In the desired WordPress template:
        <ul>
        <?php
            // This assumes you have category IDs.
            // Getting them is beyond the scope of this pos
            $args = Array('category__in'        => Array(5,6,4),
                          'showposts'           => 5
                          'template'            => 'list_with_link');
            lyzadotcom_custom_loop($args);
        ?>
        </ul>
  2. list_with_link.php might look like:
        <li id="link-<?php the_ID(); ?>" class="<?php echo $list_css_class>">
            <a href="<?php the_permalink()" title="<?php the_title(); ?>"><?php the_title(); ?></a>
        </li>

Display Your Posts Tagged ‘Banana’ from March of 2009

  1. In the desired WordPress template:
        <h3>March's Bananas</h3>
        <?php
            $args = ('tag'              => 'banana',
                     'showposts'        => -1, //show all posts
                     'monthnum'         => 3,
                     'year'             => 2009,
                     'template'         => 'month_archive_list');
            $banana_posts = lyzadotcom_custom_loop($args);
            /* Hint: You might used the returned $banana_posts to
               populate another call to lyzadotcom_custom_loop(),
               e.g. 'post__not_in' => [ids from $banana_posts]
               to avoid duplicating posts!
            */
        ?>
  2. month_archive_list.php might look like:
        <div class="archive_post" id="archive_post-<?php the_ID(); ?>">
            <?php echo $loop_count; ?> of <?php echo $loop_size; ?> Bananas:
            <strong><?php the_title(); ?></strong><br />
            <?php the_content(); ?>
            <?php edit_post_link(); ?>
        </div>

FAQ (In Which I Anticipate Questions)

Will this work with pages as well as posts?
Yes. Sure. Just fine! Anything that query_posts() can do, I can do too!
Why isn’t this a plugin?
It took me hours just to write this post; I’ve got stuff to do! If there’s a lot of interest, maybe I’ll consider it.
I found a bug/horrible security hole/idiocy?
Please let me know! Gently! Comments to this post is a fine method to do so.
How is this bad boy licensed?
GPL. Do with it what you will!
OMG! Don’t you know about XYZ plugin? It totally does this, but better!
Nope! But I’d like to!

Download, with Examples

I’ve gone ahead and zipped up some stuff for you:

  • a functions.php file with the function in it (add it to yours)
  • Several example files in a post_templates directory
  • Example.php with several calls to the function

Download ZIP

The Five Most Common Arguments for Native iPhone Development

There are five common arguments for why iPhone applications need to be built using native code instead of web technology. Three of the arguments either don’t apply in all cases or are simply wrong.

The five most common arguments for native app development are:

  1. Offline Mode — The ability to continue to use an application when you are not connected to the Internet.
  2. Findability — If you’re not in the App Store, people won’t be able to find your application.
  3. Performance — Javascript on mobile is too slow to use for application development.
  4. Device Attributes — The need to access things like the camera, gps and the accelerometer.
  5. Monetization — The ease with which people can and will buy your application.

These five reasons are also provided to argue for native app development on other platforms like Android and Blackberry as well.

Let’s take a look at each argument in more detail and evaluate their accuracy.

Five photo courtesy Flickr user boklm published under Creative Commons.

Offline Mode

False

The Offline Mode argument is that when you build an application using web technology that you must be connected to the Internet in order to use the application.

This makes native applications more useful in a mobile context where people may lose connectivity periodically as they move from place to place.

However, this argument is simply false as far as the iPhone is concerned.

On July 11, 2008, the iPhone OS 2.0 was released. With the 2.0 release, we saw not only the creation of the App Store and the first native applications, but also a new version of Mobile Safari that supported the HTML5 Web Storage and Offline Application Cache.

To summarize, there has never been a point in time when you could build native iPhone applications when you couldn’t build web applications that supported offline usage..

Findability

Unintentionally Misleading

The basic premise of the findability argument is that if you aren’t in the iPhone App Store, that no one will find you.

In the early days of the App Store, this was true. Simply having an decent application in the App Store often enough to move units.

However, the App Store now contains 65,000 applications. Developers find it difficult to stand out in the App Store, and consumers find it difficult to find applications that match their needs.

App Store wall display at WWDC courtesy Flickr user liquidx published under Creative Commons

When it comes down to it, Apple isn’t a search engine company. It is facing challenges that Google solved years ago, but without the tools and data that Google and Amazon have at their disposal. For example:

  • Google’s Page Rank innovation made it possible for network effects to be used to determine what web pages have the most value based on the number and quality of inbound links. Because the App Store is sequestered in iTunes and not on the web, inbound links cannot be used to determine value.
  • Without Page Rank or similar mechanisms, Apple has been using keyword tools to provide search results. This has led to a revival of black hat search engine spamming techniques in the App Store. Apple’s attempts to address this spamming have been hamfisted and resulted in the good being punished with the bad.
  • If you compare the App Store to other store fronts like Amazon, the App Store lacks the ability to narrow your search results by other metadata associated with a product.

The App Store market has many parallels to the early days of the web. We used to browse the web looking for cool things, but at some point the number of options became overwhelming and search became the dominant paradigm. We’ve moved into the search phase for the App Store, but the tools aren’t sufficient to the task.

The reality is that findability alone is not enough reason to build a native application. No matter what technology you use, you need a marketing plan.

Performance

Depends on the type of application

No one can argue that web technology is as fast as native application. What we can argue is that for certain types of applications, web performance is more than sufficient.

Here are some things to keep in mind when it comes to performance:

  • Javascript performance keeps getting faster — Browser manufacturers have been competing to see who can make the fastest browser. Browsers have seen significant improvements in the last two years. This emphasis on speed has made it into the iPhone. The most recent version of the iPhone OS processes javascript 3 times faster than the previous version.
  • Web developers can build faster applications — Most web developers are still not aware of the research done by Yahoo and Google on what makes web pages load more quickly. Web developers need to test their mobile code using tools like Yahoo’s YSlow and Google’s Page Speed plugins for Firefox. If developers can’t optimize for desktop browsers, they won’t succeed on mobile.
  • Use hardware accelerated css — The iPhone also offers hardware accelerated css transformations, animation and 3D. Using these css tools, you can build smooth flowing effects that rival native applications as shown by the cover flow example built in Safari shown in the video below.

The final thing thing to keep in mind is that web technology isn’t perfect for all applications. Most immersive games should be built using native code.

However for numerous applications, web technology performance is more than sufficient.

Device Attributes

Real issue

GPS access was provided in the latest iPhone OS release, but the other device attributes like camera, accelerometer and compass are still not accessible in the browser.

Photo of person taking photo of themselves using iPhone

iPhone self portrait courtesy Flickr user davemmett published under Creative Commons

The good news is that mobile phone manufacturers seem to be taking seriously the need to provide access to these attributes. The Palm Web OS is great example of exposing all of these attributes in javascript.

In July, the W3C chartered the new Device APIs and Policy Working Group to work on defining standard ways to access these device attributes.

In the meantime, usage of hybrid applications (which I will talk about later) provide a workaround for web access to device attributes.

Monetization

The Major Problem for the Mobile Web

The ability for people to play for your web application on their mobile device easily is the biggest problem facing the mobile web.

The App Store solves the payment problem elegantly. Consumers can quickly buy applications and have the purchase put on their credit card stored by iTunes. Developers know that they will get paid, how frequently, and what percentage of the transaction that Apple will take.

Photo of Innerfence system from Apple iPhone Ad

Innerfence iPhone Credit Card Terminal as featured in Apple iPhone ad.

Solutions like Bango have tried to solve this problem for the mobile web by brokering deals with all of the various carriers. Unfortunately, the end result is a inconsistent transaction fees per carrier and country and major gaps in service (e.g., no Verizon support).

Given the alternative, solutions like Bango are a tremendous step forward, but it still isn’t simple enough for developers and consumers.

Finding a good solution for mobile payments is the number one thing holding up the mobile web right now.

That said, there is cause for hope. Nokia recently launched Nokia Money. Apple is rumored to be “considering creating a service that would allow iTunes Store account holders to use those accounts to make purchases on participating third-party sites.”

And nearly every carrier seems to be looking for ways to allow people to pay for their groceries using their mobile phone.

If we reach the point where we can buy a bottle of water using our mobile phone, I’m certain we’ll be able to pay for products and services on the Internet.

Hybrid Frameworks Address Shortcomings

Out of the five original arguments for native applications, the two that pose the biggest challenge for web technology are Device Attributes and Monetization. Both of these shortcomings are addressed by hybrid applications.

Hybrid applications take a web rendering engine and wrap it in a native code framework. This allows developers to access device attributes via javascript in their web applications.

And because the application is wrapped in native code, the application can be sold and distributed via the iPhone App Store.

In fact, the same core code can be reused on multiple smart phone platforms like iPhone, Android, Blackberry, Windows Mobile, and Nokia.

Some of the hybrid application frameworks are:

People are doing amazing things with these frameworks and are currently selling their applications in the various app stores. The following video shows a game built using Phone Gap that is currently available for purchase in the iPhone App Store:

Native vs. Web Applications

Over the last year I’ve heard a lot of people argue that building anything using web technology, particularly for the iPhone, isn’t a viable option. These five reasons are the main arguments I hear over and over again.

However, three of these arguments don’t apply in all situations and the other two can be addressed with a hybrid application strategy.

There are tremendous benefits to building an application using web technology from a platform portability perspective. Not to mention that you can draw on a larger talent pool using web technology than you can if you build using Objective C.

So in the short term if you want to use web technology to build applications, hybrid frameworks will allow you to do so. In the long run, I hope the mobile web advances to the point that they are no longer needed.

The key is to evaluate each product that you want to develop, the markets you want to serve, and determining which combination of technology will accomplish your goals.

There is no “right answer” between native and mobile web applications other than the right answer for a particular application based on its design, functionality and business plan.