Semantic web development and publishing

Mobile Drupal (part 3): Code

Previous articles have discussed the conceptual groundwork and setup of mobile sites in Drupal. It’s now time to look at a number of themes and modules which will help you in your endeavours. We’ll also cover a number of custom fixes which can be made to the HTML, CSS and JS in your site.

Mobile themes

Funnily enough, the selection of the mobile theme is looking to be one of the least important technical consideration with the whole mobile site. It’s one area where I am not in the best position to comment on the various merits of themes as I haven’t really tested theme all. I went with Nokia Mobile because it seemed to have a solid base, being based on code developed by Nokia. That said, I did have to make a number of changes to it to get it to work in with my site. Be prepared to get your hands dirty with page.tpl etc. The Adaptivetheme Mobile theme looks quite promising, being a sub theme itself it would naturally fit well with a desktop theme derived from the same base.

Nokia Mobile
“Provides different presentation layers to best serve basic devices and high-end smartphones.”
Mobile Garland
Garland inspired mobile optimized Drupal theme intended to be used with a mobile optimization module Mobile Plugin.
Adaptivetheme Mobile
Hurrah! A mobile sub theme. “Adaptivetheme Mobile is a subtheme for Adaptivetheme. It is designed purely to build Drupal mobile themes for mobile web devices (for mobile websites).”
“intended to return only clean HTML with no styling (images and styling in content is maintained)
“Display a mobile, portable format.”

Mobile modules

There are a lot of options available to you when it comes to deploying modules to help you with your task. I am very much of the mind that modules should only be deployed if they are fit for the task and don’t introduce too much overhead or code you don’t understand. My aim is to keep things as “pure” as possible. In many cases you may be better writing your own custom code if you feel comfortable doing that.

Many tutorials recommend going with Domain Access and Mobile Tools with Browscap. It is a combination which could work well for you. However, I ended up not deploying any of these modules, chosing to go my own way. I’ll walk through each of the modules, their main features and why I went the way I did. It basically boiled down to the fact that Apache, settings.php and my own custom tweaks got me most the way there.

Domain Access

Domain Access is a popular suite of modules which can be used to manage (sub) domains for a (mobile) site. It is exceedingly well documented and structured. It looks to be a high quality module which supports a lot of functionality. Many mobile tutorials speak highly of it and recommend it for mobile sites.

Knowing relatively little about the module I reviewed its main features to see what it had to offer a mobile installation. From my quick review I have been unable to find anything compelling for the problem set I was facing. That said, if your mobile site is to diverge significantly from the desktop site you may find that some of the customisation features quite useful. There may well be stuff that I am missing and would be happy to be enlightened. The relevant features are as follows:

  • Domain Access: The core module allows for (sub) domains to be registered. This is really just the basic setup for the modules. In order for this to work your DNS and VirtualHosts need to be set up as you normally would for a multisite. ie. each domain pointing to the IP of your Drupal installation.
  • Domain Alias: It is possible to define domain aliases for each registered (sub) domain. eg -> Alternatively, this result could be achieved by adding some aliases in you VirtualHost section in Apache.
  • Domain Theme: Allows you to define a theme for each (sub) domain. Alternatively, if you were using a multisite setup (or some conditional logic) you could set the default theme in settings.php.
  • Domain Config: Offers an extensive set of site configuration options including email, slogan, mission, footer, frontpage, anon user, admin theme, time, cache, menu mappings. Most of these tweaks can be achieved by traditional means. Conf variables can be overridden in settings.php. Custom menu blocks can be placed into regions.
  • Domain Source: Source domain for linking to content. This ensured that some links are rewritten to point to main site. In a mobile setup you would want the site to operate as normal (no rewriting). The duplicate content can be fixed with canonical URL link in the head.

Mobile Tools

Mobile Tools is a popular module which has a bunch of handy utility features most mobile sites could use.

  • Detection of UA and redirect based on Browscap and WURFL:Possible to map user agents to themes. More sophisticated if Browsercap or WURFL is used. This redirection should be taking place outside of PHP so I am a fan of doing this in Apache rewrite rules or maybe even a caching/reverse proxy layer. This alternative approach has been discussed above.
  • Block telling users of Mobile site: Helpful but easy to add manually.
  • Panels integration: No doubt very helpful if you are using Panels, as Panels own a path and that’s it. This could be a deal breaker so this could be essential. Personally, I stuck to very simple design so Panels wasn’t an issue for me.
  • Permissions integration: Mobile roles can be used to turn block aspect of the site based on permissions. This is a really good idea and a neat way to turn stuff off.
  • Change number of nodes on homepage: Helpful but could be done with a different view exposed as a block.
Drupal Support for Mobile Devices [Rachel Scott]
Overview of the Mobile Tools module with screenshots.
Mobilize Your Drupal Site with Mobile Tools
Overview of the Mobile Tools module describing multisite setup.

Mobile Plugin

Wide range of features. Tackles some practical isses such as word breaks, scaling images, video embedding, filtering JS. Does device detection and provides own mobile theme. Unfortunately the doc specifies that “Page caching must be off to support multiple themes!”. This warning would put most people off. Does this apply even if two sites are being used?


A popular module which returns capabilities based on user agent. The module will fetch updates to a database of browser user agents. Integrates with Mobile Tools.


“The WURFL module helps you in detecting the device capabilities of the mobile device visiting your website.” Integrates with Mobile Tools. Knowing the capabilities of a device at a very fine level of granularity could be helpful if you are into eeking out every enhancement you can. the question is whether you need this level of control.

Module code vs Theme code

Adding a mobile version of your site will make you think about code duplication issues. If you have custom logic in your theme for the desktop site then there is a pretty good chance that a large chunk will be copied across to the mobile site. Bad news. Much of what makes it into themes is not 100% concerned with presentation. It’s hard to draw a line but if the code is required for mobile and desktop then it is a good candidate for being factored out into a more central place such as a module. Less code means less work for you in the future. If you do have custom code in template.php then take a look through it and see what can be moved.

Custom content

Not all changes can be made in the theming layer, it will be necessary to change and optimise the content served.

Custom blocks

Managing block configuration (region, order, title, paths, permissions, etc) is a right royal pain in the you know where, especially if you have a lot of blocks and you need to deploy across dev, staging and production. Going into the blocks admin interface and moving stuff around, editing, saving and repeating gets old real quick. Configuration concerns such as this have been overcome largely though code from DevelopmentSeed. Features to hold logic and configuration for grouped functionality. Features work nicely together with Context, which allows for Blocks to be positioned according to an overarching context. Cool. Context could be the answer we are looking for. It certainly is for a normal desktop site.

However, when it comes to configuring blocks for a mobile site, Context only knows about the current theme. This is a known issue for Context. There is another module, called Features Extra which possibly offers a way to capture config info for blocks, however it too suffers with themes. AFAICT it still isn’t possible to capture block config with multiple themes. Bummer. I’d be interested to know if there are solutions here.

In the meantime you can manually configure blocks the old school way but it really isn’t ideal.

Custom modules

This is one area I was unable to nail as well. In a few places it would have been very handy if I could have turned off a module dynamically to make the mobile site a bit simpler, eg. colorbox, admin menu. AFAICT there is no way to do this. Tracing the calls during bootstrap, I see that module_load_all() is called very late in the procedure at _drupal_bootstrap_full(). module_load_all() calls module_list() which gets all active modules. It would be great if module_list() could look to conf variables to respect a stop filter of modules. Not going to happen I know, but would be handy.

This is where the permissions integration in Mobile Tools could really shine. Instead of disabling a module you could control the operation of a module via permissions. Most modules should have permissions limitations on functionality and so can be turned off for the mobile site.

One way to work around this is to mop up the HTML/JS/CSS in the theme layer. This approach is ugly, error prone and brittle, but does hold some promise. You will find recipes similar to the following around the traps:

* Implementation of hook_preprocess_page().
function mw_mobile_preprocess_page(&$vars) {
if (!cuf_mobile_is_mobile()) { return; }
// Strips out JS and CSS for a path.; //
// WARNING: The code below messes up jQuery Update even when no scripts are
// replaced. Use at own risk.
$remove_csss = array(
//’colorbox’ => array(‘/styles/default/colorbox_default_style.css’),
$remove_jss = array(
//’colorbox’ => array(‘/js/colorbox.js’, ‘/styles/default/colorbox_default_style.js’),
// JS
$scripts = drupal_add_js();
if (!empty($vars['scripts'])) {
foreach($remove_csss as $module=>$paths) {
foreach($paths as $path) {
$module_path = drupal_get_path(‘module’, $module);
unset($scripts['module'][$module_path . $path]);
$vars['scripts'] = drupal_get_js(‘header’, $scripts);
// CSS
$css = drupal_add_css();
if (!empty($variables['css'])) {
foreach($remove_csss as $module=>$paths) {
foreach($paths as $path) {
$module_path = drupal_get_path(‘module’, $module);
unset($css['all']['module'][$module_path . $path]);
$vars['styles'] = drupal_get_css($css);

In the end I gave up on going down this path because I was running into a problem with jQuery not being updated, leading to JS errors on the page. It was too brittle for me to trust.

For me, the take away is that you are pretty much stuck with using the some modules if you are sharing the database. You just have to be aware of this when designing the site. The only way to solve this is to place some conditional login into you own custom modules which checck for the site being mobile. If you are using contrib then things will be a trickier.

You may desire have custom primary and secondary links for the mobile site. If you really have thought mobile first then maybe the menus will be the same :) but there’s a good chance they will be paired down for the mobile site. It’s not possible to easily define two sets of primary menuas, one for mobile and one for desktop. However, Mobile Tools offers a way to map primary/secondary menus to other menus. There are two other options though if you don’t want to install Mobile Tools.

  • Define different menus (eg. Primary Mobile) and drop them into desired region using Blocks. Comment out the primary links in page.tpl.
  • Programmatically set the links in a custom module

In the end I just programmed these menus in code in my mw_mobile module because the menus had some logic in them for login/logout links:

* Implementation of hook_preprocess_page().
function mw_mobile_preprocess_page(&$vars) {
if (!mw_mobile_is_mobile()) { return; }
// Completely hijack the primary menu and set it from code. This allows
// the primary menu to be managed in features for the desktop site. We just
// need to oveerride it here.
$vars['primary_links'] = array();
$vars['primary_links']['blah'] = Array (
;’title’ => t(‘Blah’),
‘attributes’ => Array(‘title’ => ‘Blah.’),
‘href’ => ‘blah’
// etc

Custom Views

This section really gets back to the “mobile first” and “responsive web design” concepts we discussed earlier. Views are very powerful and there is a strong temptation to make them as sexy as possible, displaying images, extra content, edit links, star ratngs and the like. Step back and take a look at what you are doing. It maybe possible to design a simple display which works well in mobile and desktop.

Often you really do want to display rich tabular information in the desktop version of the site. In these cases you shouldn’t compromise – you’ll need to create different versions. In these cases progressive enhancement doesn’t really cut it as you want to return more content, not just tweak the presentation.

If it is a View Block which is giving you grief then just make a mobile version and use that instead. Use the block system to place different blocks for the different themes.

If it is a View Page then you could be in trouble as the View takes hold of the path and it is difficult to customise that on a per site/theme basis. One solution is to expose the View as a Block (with a mobile version) and then place that block on a Page (node) or menu path you have made. In this case the page is acting like poor man’s Panels. A bit ugly but it works.

If you are lucky you might be able to define a custom formatter which just returns a blank (or a simple version) if the site is mobile.

A final alternative is to define View templates which have some conditional logic in them. This is possibly the purest way but I think it could become a maintenance issue. We are trying to minimise duplication and effort – creating new files with extra display logic is best avoided.

Custom Panels

I’ll come clean here and own up to not having caught the Panels bug just yet, being content to limit my degrees of freedom. Yes, I am that boring :) Anyway, Panels faces a similar problem as Views Pages in that they are tied to a path which isn’t scoped by a theme (as Blocks are). In this case, Mobile Tools could be quite helpful and showing different layouts for a Panel.

Custom Variables

Drupal can be configured with a whole bunch of variables, many of which are available for editing in the site configuration part of the site. Fire up phpMyAdmin and browse the variable table to get an idea of what is available. These variables are site wide and as such will apply equally to the mobile and desktop versions in our multisite setup. It is possible to override these variables for the mobile site by tweaking settings.php. We have already seem this in action for the default theme. You can do it for other things as well. Mobile Tools offers an interface for this but you can do it manually. I have found that only a small number of rarely changed variables need to be tweaked and so settings.php is a viable option.

$conf = array(
‘theme_default’ => ‘mw_nokia_mobile’,
‘googleanalytics_account’ => ‘UA-xxxxxxxx-2′,

Output tweaks

Mobile devices have special requirements, not all of which could be handled by the theme templates alone. The metadata and content of the sites may need some special work. The Rethinking the Mobile Web slideshow above noted that we need to adjust and compress content to make it palettable for mobile. This is where a lot of that nasty work happens. You’ll probably only run into these issues after testing the site for real. No doubt you will have your own special set of problems to deal with. The Plugin module plugs some of these holes.


You probably have a bunch of ImageCache presets defined for your site, which may or may not be captured in Features config. These presets may be outputting images at a size which is too big for the mobile site. Anything wider than 100px is probably too big. You are aiming to be frugal with bandwidth as well as screen real estate. Time to get shrinking those images. See hook_preprocess_page code below.

Secure Login

If you are using the Secure Login module, you may run into difficulties if you have the multisite setup. The way I had Secure Login configured was to specify the URL to redirect to. This URL is of course for the desktop version of the site and your mobile users will be routed to the desktop site after they log in. They may not notice it if URL redirecting is working for mobile users but we would want to minimise redirects such as this.

It is possible to leave the Secure Login URL blank and then it will apparently use the base_url defined in settings.php. This would be a sensible approach, however, I was having all sorts of path difficulties with ImageCache if I specified these URLs. Don’t know why. Anyway, the easiest solution for me was to stick with the hardcoded URL for Secure Login and then to fix it up in the module.

* Implementation of hook_preprocess_page.
function mw_nokia_mobile_preprocess_page(&$vars) {
// imagcache images are shrunk to mobile size
$fix_regions = array(‘content’, ‘right’, );
foreach($fix_regions as $fix_region) {
// secure login will target the url you entered into the site config.
// there might be a better way to fix this but we just string replace here

* Secure login hardcodes the URL entered in the config: securelogin_baseurl
* This will be the desktop version of the site. We need to change it to the
* mobile version. There isn’t an obvious way to do this via code, unless you
* write your own hook_form_alter but that would usurp the function of
* securelogin. So we just mop up afterwards. These login pages will be
* cached anyway.
* eg ->
* NB: It MIGHT be possible to leave out securelogin_baseurl in the config and
* manually set the base_url in the settings.pgp for the site. However, when
* I did settings like this in the past I ran into problems… can’t remember
* what they were now… So this might be a solution which would avoid the need
* for this code.
function _mw_nokia_mobile_fix_secure_login_form(&$text) {
if (!module_exists(‘securelogin’)) {
$sec_url = variable_get(‘securelogin_baseurl’, ”);
if (empty($sec_url )) {
$new_url = str_replace(‘https://’, ‘https://m.’, $sec_url);
$pre = ‘<form action=”‘;
$paths = array(‘/user/login’, ‘/user/register’);
foreach($paths as $path) {
$search = $pre . $sec_url . $path;
$replace = $pre . $new_url . $path;
$text = str_replace($search, $replace, $text);

* Map imagecache presets to smaller presets. This is VERY UGLY because you
* need to correct for the width and height as well. Sorry to have impinged
* upon your senses!
* Adapted from
function _mw_nokia_mobile_fix_imagecache(&$text) {
if (!module_exists(‘imagecache’)) {
// mappings. ignore: slider_perview, slider_thumbnail
// old ic, old width, old height, new ic, new width, new height
$mappings = array(
array(‘thumbnail_small’, ’83′, ’83′, ‘mobile_thumbnail’, ’75′, ’75′),
array(‘thumbnail’, ’100′, ’100′, ‘mobile_thumbnail’, ’75′, ’75′), // thumbnail last
// fix
$file_url = base_path().file_directory_path();
foreach($mappings as $mapping) {
list($old, $old_w, $old_h, $new, $new_w, $new_h) = $mapping;
$old_path = $file_url .’/imagecache/’ . $old;
$new_path = $file_url .’/imagecache/’ . $new;
$old_class_size = ‘imagecache-’ . $old . ‘” width=”‘ . $old_w . ‘” height=”‘ . $old_h . ‘”‘;
$new_class_size = ‘imagecache-’ . $new . ‘” width=”‘ . $new_w . ‘” height=”‘ . $new_w . ‘”‘;
$text = str_replace($old_path, $new_path, $text);
$text = str_replace($old_class_size, $new_class_size, $text);

Search snippets URLs

I’m not sure if the following applies to ordinary Drupal search but it certainly does with Apache Solr Search. The URLs for the individual search results were coming back with the fully qualified URL pointing to the desktop site. This was solved by a bit or mopping up in a base feature, mw_base.

function phptemplate_apachesolr_search_snippets($doc, $snippets) {
// mobile site?
$mobi = module_exists(‘cuf_mobile’) && cuf_mobile_is_mobile();
$url = $doc->url;
if($mobi) {
$url = str_replace(‘http://’, ‘http://m.’, $url);


The combination of Location and GMap is a very popular one on Drupal sites. GMap module is currently targetting version 2 of the Google Maps API. Version 3 offers a bunch of new features for mobile devices.

Google Maps JavaScript API V3
“The Google Maps Javascript API lets you embed Google Maps in your own web pages. Version 3 of this API is especially designed to be faster and more applicable to mobile devices, as well as traditional desktop browser applications.”

For now users of GMap are stuck on v2 but there is active development in GMap to bring the module up to support v3.


WYSIWYG textareas do not display properly on some mobile devices. You need to turn them off.

WYSIWYG on mobile devices
Discussion on WYSIWYG issue queue regarding the difficulties faced on a variety of devices. End conclusion appears to be that you need to turn it off for best results.

How to turn of WYSIWYG? After a bit of poking around I worked out that setting the ‘format’ for the textarea to an empty array was the way to do it. The following code in your mobile module will do the trick for comment and node bodies. If you have other forms which need fixing then you’ll need to do a bit of debugging to suss out what the form_id and element id is.

* Implementation of hook_form_alter.
function mw_mobile_form_alter($form_id, &$form) {
if (!mw_mobile_is_mobile()) { return; }
// turn off wysiwyg forms for textareas. you need to manually find the form
// with wysiwyg and then work out its id and where ‘format’ is.
//print $form_id['#id'] . ‘ ‘;
$no_wysiwyg = array(
‘comment-form’ => ‘comment_filter’,
‘node-form’ => ‘body_field’
$id = $form_id['#id'];
if (array_key_exists($id, $no_wysiwyg)) {
$form_id[$no_wysiwyg[$id]]['format'] = array();


The primary and secondary tabs which appear on the top of the page tend to take up a fair amount of horizontal space and will be the element which causes horizontal scrolling. These tabs can be easily restyled to display as a traditional list. You can also update page.tpl and move the tabs to the bottom of the page so they don’t detract from the main content.


Flash is not going to work in iPhones, iPad and many other devices. It’s also heavy and resource intensive. As such it shouldn’t reallu be used for content or navigation on the mobile site. The exception might be to show video content, however, even in this case there might be better workarounds.


Suckerfish provides dropdown menus which can take up a lot of room. The hover metaphor doesn’t work for touch devices. Best avoided.

Make sure that links are big enough to clickable: large with enough whitespace around key navigation links.


Mobile devices such as the iPhone and iPad may have a special app to handle YouTube videos natively so clicking on a link is preferable than displaying an embedded video.


Yes – ads can be optimised for mobile as well.

Google Mobile Ads
“In May 2010 Google acquired AdMob, a leading mobile advertising network that developed innovative mobile-specific ad units and solutions, to significantly enhance our mobile display ad services for publishers.”


Testing an afterthought? Never :) The fact is that a lot of the hard work is in getting over the config hurdles. once the mobile site is up and running you are going to uncover a bunch of things you never dreamed about. Here’s a quick checklist of things to look out for:

  • UA testing and redirect working.
  • Boost/Drupal Core page caching working.
  • SSL login working OK.
  • Basic functionality and navigation operational.
  • Theming is up to scratch.
  • Site fulfills its goals.

This article is the third in a four part series on mobile sites in Drupal.

  1. Mobile Drupal (part 1): The groundwork
  2. Mobile Drupal (part 2): Site setup
  3. Mobile Drupal (part 3): The code
  4. Mobile Drupal (part 4): Conclusions

Feel free to comment if you have any other tips, recommendations or corrections. The example code presented is for Drupal 6 only and not necessarily production ready.

Be Sociable, Share!


  1. Brad
    Posted September 15, 2011 at 8:14 am | Permalink

    Thank you for the “Custom Variables” section. The Google Analytics example really inspired me. Combing the ‘variables’ table resulted in another gem, turning off Mobile Tools redirection on a per site basis.

    $conf = array(
    'mobile_tools_redirect' => '0',

  2. Posted October 20, 2011 at 12:55 am | Permalink

    This is really very helpful tutorial.

  3. Roger Saner
    Posted October 28, 2011 at 10:29 am | Permalink

    Thanks for the helpful guide – it got me started nicely :)

    I’m running my mobile site off a subdomain (so I have and Both domains point to sites/ and then in my settings.php I do a check, and if the url starts with “m” then I set my mobile theme as the default.

    I wanted to use contexts to do my block placements in my mobile theme – but as you say, it’s not easy. Possible, though! First, I added the following to settings.php

    $parts = explode('.', $_SERVER['HTTP_HOST']);
    if ($parts[0] == 'm') {
    $conf['theme_default'] = 'fusion_mobile';
    $conf['site_frontpage'] = 'mobile';

    That sets the theme as default and gives me a custom frontpage that I want to show for mobile devices.

    Then I created my context and did the block placements for it. Note: I didn’t add any conditions to activate the context, since I’m going to do that in a module, like so:

    function mymodule_init() {
    if ($GLOBALS['conf']['theme_default'] == 'fusion_mobile') {
    $context = context_load('ui_mobile_sitewide');
    context_set('context', 'ui_mobile_sitewide', $context);

    …and that loads my context whenever my theme is active. It works with aggressive page caching too.

  4. Posted October 28, 2011 at 6:20 pm | Permalink

    Good stuff Roger. That looks a nice way to do it.

    Admittedly, I should have poked around with context a bit more to work out how to create my own before writing this article. It’s not that hard. A little while after writing the article I noticed that Mobile Tools supports Context now. That might be another option.

  5. Roger Saner
    Posted November 4, 2011 at 3:10 pm | Permalink

    The Mobile Tools way looks great, and works well – if you can use Mobile Tools on your site. I can’t on mine, since I’m running varnish in front of drupal, so I’ve got to do my device detection in varnish before deciding which subdomain to serve.

    Unfortunately, the WURFL data has recently become commercial and requires a hefty fee to use with varnish (and there’s no written integration yet). I’m looking at using Wikimedia’s varnish configuration which uses a few more regular expressions than Fangel’s method. It’s going to miss a whole bunch of older phones, but it seems to be good enough for wikimedia. Looks like maintaining my own set of regex is the way to go…but there’s GOT to be a better way!

One Trackback

  1. [...] This post was mentioned on Twitter by Drupal Updates. Drupal Updates said: Drupal Planet: Cruncht: Mobile Drupal (part 3): Code [...]