How to detect mobile devices and present them a specific theme?

I would like to create a new modified version of my theme (check my profile if needed) to present to visitors if I detect that they are visiting the site from a hand-held device, like iPhone, Android, etc.

  1. How to detect if the request is coming from a mobile device/browser?
  2. How can I load and present them a dedicated theme?

More Info: My theme is not fluid. It has a fixed width of about 976px (676px content + rest is left sidebar). I do not want to revolutionize the theme but I feel it is to large for 320×480 and 800×480 phones. Probably I will remove the sidebar or at least move it to right and do other small adjustments.

Related posts

Leave a Reply

6 comments

  1. Like most others, I highly recommend using WPTouch. However, it’s built more to support blogs than other website formats, so I know it’s not the panacea of mobile solutions (I run my portfolio on WordPress as well as my blog, and my portfolio looks like **** in WPTouch).

    So I did take a look at the code to find the relevant portions that you’d need to use to replicate the mobile browser detection. Firstly, as mentioned by Jan Fabry, is a list of mobile browser user agents. WPTouch includes a default list, but also allows you to add custom user agents with a setting or with a filter called wptouch_user_agents:

    function bnc_wptouch_get_user_agents() {
        $useragents = array(           
            "iPhone",                                // Apple iPhone
            "iPod",                                  // Apple iPod touch
            "Android",                               // 1.5+ Android
            "dream",                                 // Pre 1.5 Android
            "CUPCAKE",                               // 1.5+ Android
            "blackberry9500",                        // Storm
            "blackberry9530",                        // Storm
            "blackberry9520",                        // Storm v2
            "blackberry9550",                        // Storm v2
            "blackberry9800",                        // Torch
            "webOS",                                 // Palm Pre Experimental
            "incognito",                             // Other iPhone browser
            "webmate",                               // Other iPhone browser
            "s8000",                                 // Samsung Dolphin browser
            "bada"                                   // Samsung Dolphin browser
        );
    
        $settings = bnc_wptouch_get_settings();
        if ( isset( $settings['custom-user-agents'] ) ) {
            foreach( $settings['custom-user-agents'] as $agent ) {
                if ( !strlen( $agent ) ) continue;
    
                $useragents[] = $agent; 
            }       
        }
    
        asort( $useragents );
    
        // WPtouch User Agent Filter
        $useragents = apply_filters( 'wptouch_user_agents', $useragents );
    
        return $useragents;
    }
    

    The meat of the plugin, though, is a class:

    class WPtouchPlugin {
        var $applemobile;
        var $desired_view;
        var $output_started;
        var $prowl_output;
        var $prowl_success;
    
        ...
    

    The plugin’s constructor (function WPtouchPlugin()) first adds an action to the plugins_loaded hook to detect the mobile browser’s user agent and set $applemobile to true. Here’s the specific function:

    function detectAppleMobile($query = '') {
        $container = $_SERVER['HTTP_USER_AGENT'];
    
        $this->applemobile = false;
        $useragents = bnc_wptouch_get_user_agents();
        $devfile =  compat_get_plugin_dir( 'wptouch' ) . '/include/developer.mode';
        foreach ( $useragents as $useragent ) {
            if ( preg_match( "#$useragent#i", $container ) || file_exists( $devfile ) ) {
                $this->applemobile = true;
            }       
        }
    }
    

    Now the plugin knows you’re using a mobile browser (according to the browser’s user agent). The next meaty part of the plugin is a set of filters:

    if ( strpos( $_SERVER['REQUEST_URI'], '/wp-admin' ) === false ) {
        add_filter( 'stylesheet', array(&$this, 'get_stylesheet') );
        add_filter( 'theme_root', array(&$this, 'theme_root') );
        add_filter( 'theme_root_uri', array(&$this, 'theme_root_uri') );
        add_filter( 'template', array(&$this, 'get_template') );       
    }
    

    Each of these filters calls a method that checks whether or not $applemoble is set to true. If it is, then WordPress will use your mobile stylesheet, your mobile theme, and a mobile post/page template instead of the default ones for your theme. Basically, you’re overriding WordPress’ default behavior based on whether or not the browser being used has a user agent that matches your list of “mobile browsers.”

    WPTouch also includes the ability to turn off the mobile theme – when you visit a WPTouch site on an iPhone, there’s a button at the bottom that allows you to view the site normally. You might want to consider this as you build your own solution.

    Disclaimer: All of the above code was copied out of the source for WPTouch version 1.9.19.4 and is protected under the GPL. If you re-use the code, your system must also comply with the terms of the GPL. I did not write this code.

  2. You might want to look at how the very popular WPtouch plugin does this. It gives a different theme for “iPhone, iPod touch, Android, Opera Mini, Palm Pre, Samsung touch and BlackBerry Storm/Torch mobile devices”. I see a list of user agents in their source code, that’s probably the key.

    Another plugin, WP-Wurfled, uses the extensive Wireless Universal Resource File database. This constantly-updated database of mobile devices also contains lots of capability info, so you know server-side the screen resolution of the device, whether it supports Flash, …

    The template_redirect action hook is often used to load custom themes, as it is almost the last moment before a real template file is included (template_include is the last hook, but that’s a filter).

  3. At the risk of not answering the question, I’d advise to not do so.

    I’ve been using iOS devices for months, and one of the first things I did back when I bought my iPad was to try to come up with CSS layout that changed its behavior based on the device used (and, originally, the screen orientation).

    At the time of writing, it’s running on my dev site (http://dev.semiologic.com/). If you test it on an iOS device, you’ll note that the layout switches from a column with sidebars on the iPad, to one with a single column based on the iPhone. (The sidebars get laid out in two columns, and the bottom boxes are laid out in two columns underneath.) You can reproduce the effect using Safari, by reducing the browser’s width.

    Anyway, as fun as it was to program, it eventually occurred to me that, at least on iOS devices, the mobile-optimized layout made things worse, not better. Safari mobile’s built-in zoom is so that, as long as your main column is 480px wide, your site is already optimized for mobile use. Add a 240px wide sidebar for a 720px wide layout, and your site fits and looks great in all:

    • 1024×768 (iPad landscape)
    • 768×1024 (iPad portrait)
    • 800×600 (users with poor eyesight)
    • 480×320 (iPhone landscape)
    • 320×480 (iPhone portrait, with the auto-zoom kicking in)

    500px + 250px also works if you’d rather have something that totals 750px, if you take the Safari mobile’s built-in zoom into account. The site will still look good and be perfectly readable on iPhones in both landscape and portrait modes.

    At any rate, getting back to your question, testing revealed that the one thing you should NOT do, is to use a layout with a flexible width. (Incidentally, WP-touch will do just that unless I’m mistaking.) Doing so leads to sub-optimal zooming. On the iPad, you can zoom in on something constrained in a 480px wide column, allowing for larger text size; something that “adjusts” to your screen’s width forces you to read tiny text, or horizontal scrolling if it’s too small to read comfortably…

  4. This is a really great script if you want to customize it, easy to integrate into wordpress.
    http://detectmobilebrowsers.mobi/

    One thing to note is that most iphone, andriod , or mobile phones users with native browser support do not want to be automatically re-directed!

    This is bad practice, give them an option via a link to a mobile version AND in the mobile version give them an option to get back to the original site.

    I repeat do not automatically re-direct your users unless your building something very specific for mobile, or you have traffic from older phones with no native browser support ( unlikely).

    • Wanted to add, one easy way to tell how important this is is through your server logs.
  5. I’ll add an alternative approach.

    Maybe you want to handicraft and finetune all the style and behavior according to very specific needs.

    I recently had to: if IE9 one thing, if iPhone a second one, if iPad a third one and so on…
    And used Chris Schuld’s Browser.php class with great results.

    The function I came up and usage examples:

    require_once('Browser.php');
    $browser_check = new Browser();
    $browser_agent = $browser_check->getBrowser();
    $browser_version = $browser_check->getVersion();
    
    function browser_check($what) {
        global $browser_agent, $browser_version;
        switch ($what) {
            case 'version':
                return $browser_version;
            break;
            case 'ie':
                if ($browser_agent==Browser::BROWSER_IE) return true;
                else return false;
            break;
            case 'mobile':
                if ($browser_agent==Browser::BROWSER_ANDROID || $browser_agent==Browser::BROWSER_IPOD || $browser_agent==Browser::BROWSER_IPHONE) return true;
                else return false;          
            break;
            case 'ipad':
                if ($browser_agent==Browser::BROWSER_IPAD) return true;
                else return false;          
            break;
            default:
                return false;
            break;
        }
    }
    
    echo "Browser Version: " . browser_check('version');
    
    if ( browser_check('ie') ) echo "Using Internet Explorer - print proper CSS";
    
    if ( browser_check('mobile') ) echo "Using iPhone, iPod or Android - print proper JAVASCRIPT";
    
    if ( browser_check('ipad') ) echo "Using iPad - print proper PHP";