Creating Mobile Sites in Drupal Using Multisites
This article provides a quick way to make your Drupal site accessible to mobile devices through two options:
- Have a one site serve multiple devices using one code base
- Use multisites to render content accordingly using one code base
Table of Contents
- 1. Overview
- Outline of what this article is all about
- 2. Function of this script
- The scripts functionality, what is does and what it does not
- 3. Skill Level
- Developer knowledge required to implement the script
- 4. Requirements
- Server set up
- 5. Files Included
- All the files included in this module
- 6. Usage
- How to use
- 7. Code
- Summary of the relevant code arrange into snippets
- 8. Configuration
- Summary of the relevant code arrange into snippets
- 9. Summary
- Overview of what has been achieved
- 10. References and additional information
- Inspiration and future developments
1. Overview
This article provides a quick way to make your site accessible to mobile devices through two options
- Have a one site serve multiple devices using one code base
- Use multisites to render content accordingly using one code base
The basis of the scripts include could be used stand-alone. The template engine used in this article is phptemplate.
2. Function of this script
The scripts included in this article checks to see if the device is a handheld browser using $_SERVER["HTTP_USER_AGENT"], and works out the best type of data to send to it using $_SERVER["HTTP_ACCEPT"] values.
3. Skill Level
Intermediate PHP and Drupal knowledge level is required. Developer must have prior knowledge of setting up multisites.
4. Requirements
The script uses PHP. This has been tested in PHP v4x and above, but it should work in any PHP environment. The script is an adaptation used on Drupal 4.5 / 6. It is untested in 4.7 and may require a few tweaks.
5. Files Included
A list of the files included in this module. Please ensure that files are uploaded to the correct location.
- settings.php
- Modifications only to this file 5.1
- themes [directory] 5.2
-
- mhtml - directory containing
page.tpl.phpfor mobile devices - imode - directory containing
page.tpl.phpfor imode web browsers - wml - directory containing
page.tpl.phpwap compatible template
- mhtml - directory containing
- detect [directory]
-
browser.php- device detection scriptbrowser.inc- text file containing list of all known mobile devicesfix_code.php- includes functions for tidying up final output
5.1 Directories within sites dependant on site set up
5.2 Screenshots, CSS, icons and additional templates can be added as required
6. Usage
Upload the detect directory to chosen location, then edit paths in settings.php accordingly. To use multisites, please see configuration for more details.
7. Code
The actual code in more detail.
Changes to settings.php set some header parameters that must be set before any content is sent to the browser. Drupal has a couple of built in headers that need to be overridden. Changes are therefore required to a couple of lines in common.inc.
// common.inc line 60 function drupal_get_html_head() { global $base_url; $output = "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"; $output .= "<base href=\"$base_url/\" />\n"; $output .= theme('stylesheet_import', 'misc/drupal.css'); return $output . drupal_set_html_head(); } // common.inc line 1875 drupal_set_header('Content-Type: text/html; charset=utf-8');
Change to the following. This overrides the default Content-Type. Note that if roll-back is required, common.inc must be reverted also.
// common.inc line 60 function drupal_get_html_head() { global $output; return $output . drupal_set_html_head(); // common.inc line 1875 #drupal_set_header('Content-Type: text/html; charset=utf-8');
7.1 settings.php
Towards the bottom of settings.php include the main file browser.php. Call the function and make some changes accordingly.
function html_fix($buffer) { return (preg_replace("!\s*/>!", ">", $buffer)); } $accept = array( "xhtml" => "application/xhtml+xml", "html" => "text/html", "wml" => "text/vnd.wap.wml", "mhtml" => "application/vnd.wap.xhtml+xml", ); $mobi = array("chtml", "wml", "mhtml"); DEFINE ('DETECT_PATH', '/path/to/detect_directory/'); // change to suit include_once DETECT_PATH .'browser.php'; $browserfile = DETECT_PATH .'browser.inc'; $fixfile = DETECT_PATH .'fix_code.php'; $or = FALSE; // Options: FALSE or keys from $accept $detect = media_type($accept, $browserfile, $or); if ((defined('MOBI') AND MOBI == true) OR in_array($detect, $mobi)) { $is_mobi = true; } else { $is_mobi = false; }
browser.php should return a key from the $accept array. $or enables complete override of the detection. This is site wide, so if $or = 'wml'; the whole site will be in wml. Paths to files should be amended also. The next snippet sets http headers and then detects if the device is a mobile and restricts the number of snippets view on the main node page.
drupal_set_header('Content-Type: '. $accept[$detect] .'; charset=utf-8'); drupal_set_header('Vary: Accept'); if ($is_mobi == true) { $conf['default_nodes_main'] = 2; $conf['anonymous'] = 'Mobile User'; }
The final part of the script sets additional headers and then automatically selects a template dependent of device.
$default_css = 'misc/drupal.css'; // default drupal style if ($detect == 'wml') { drupal_set_header('Content-Type: '. $accept[$detect] .', true'); include $fixfile; // extra file for stripping out non-wml syntax ob_start('fix_code'); $conf['theme_custom'] = 'wap'; // change to suit $conf['theme_default'] = 'wap'; // change to suit $output = ''; } elseif ($detect == 'mhtml') { $conf['theme_custom'] = 'mobi'; // change to suit $conf['theme_default'] = 'mobi'; // change to suit $output = '<meta http-equiv="Content-Type" content="'. $accept[$detect] .'; charset=utf-8" />'."\n"; $output .= '<base href="'. $base_url .'/" />'."\n"; $output .= theme('stylesheet_import', $default_css); elseif ($detect == 'chtml') { $conf['theme_custom'] = 'imode'; // change to suit $conf['theme_default'] = 'imode'; // change to suit ob_start('html_fix'); $output = '<meta http-equiv="Content-Type" content="'. $accept[$detect] .'; charset=utf-8">'."\n"; $output .= '<base href="'. $base_url .'/" />'."\n"; $output .= theme('stylesheet_import', $default_css); elseif ($detect == 'xhtml' AND $is_mobi == true) { $conf['theme_custom'] = 'mobi'; // change to suit $conf['theme_default'] = 'mobi'; // change to suit $output = '<meta http-equiv="Content-Type" content="'. $accept[$detect] .'; charset=utf-8" />'."\n"; $output .= '<base href="'. $base_url .'/" />'."\n"; $output .= theme('stylesheet_import', $default_css); } elseif ($detect == 'html') { ob_start('html_fix'); $output = '<meta http-equiv="Content-Type" content="'. $accept[$detect] .'; charset=utf-8">'."\n"; $output .= '<base href="'. $base_url .'/" />'."\n"; $output .= theme('stylesheet_import', $default_css); } else { $output = '<meta http-equiv="Content-Type" content="'. $accept[$detect] .'; charset=utf-8" />'."\n"; $output .= '<base href="'. $base_url .'/" />'."\n"; $output .= theme('stylesheet_import', $default_css); }
7.2 Themes
Themes are made using phptemplate for Drupal. They work as any other template. However, they render content slightly differently using different DTDs according to device capability. Some examples are listed below.
- wml 7.1
-
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> <card cardid="content" cardtitle="<?php print $site_name; ?>"> <?php if ($title) ?><p><big><?php print $title; ?></big></p><?php ?> <?php if ($site_slogan) ?><p><em><?php print $site_slogan; ?></em></p><?php ?> <?php print $content; ?> <p><a href="http://mobiforge.com/#menu">Menu</a></p> </card> <card cardid="menu" cardtitle="Menu"> <?php if (isset($primary_links)) { ?> <p><?php print theme('links', $primary_links) ?></p> <?php } ?> </card> </wml>
- mhtml
-
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="<?php print $language ?>" xml:lang="<?php print $language ?>"> <head> <title><?php print $head_title ?></title> <link rel="Home" href="/" title="Network Home" /> <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /> <meta http-equiv="Content-Style-Type" content="text/css" /> <?php print $head ?> <?php print $styles ?> </head> <body> <div id="home"> <?php if ($logo) : ?> <a accesskey="1" href="<?php print $base_path ?>" title="<?php print t('Home') ?>"><img src="<?php print($logo) ?>" alt="<?php print t('Home') ?>" border="0" /></a> <?php endif; ?> </div> <?php if ($site_name) : ?> <div class="site-name"><a href="<?php print $base_path ?>" title="<?php print t('Home') ?>"><?php print($site_name) ?></a></div> <?php endif;?> <?php if ($site_slogan) : ?> <div class="site-slogan"><?php print($site_slogan) ?></div> <?php endif;?> <?php if (isset($primary_links)) { ?> <p><?php print theme('links', $primary_links) ?></p> <?php } ?> <?php if (isset($secondary_links)) { ?> <p><?php print theme('links', $secondary_links) ?></p> <?php } ?> <?php print $content; ?> <?php if ($sidebar_left != ""): ?> <div id="sidebar-left"> <?php print $sidebar_left ?> </div> <?php endif; ?> <?php if ($footer_message) : ?> <div id="footer-message"> <p><?php print $footer_message;?></p> </div> <?php endif; ?> </body> </html>
These are stripped down versions of phptemplate. Some variables, that are unnecessary for a mobile device, have been removed. imode's template is similar, except it is written in Compact HTML. xhtml and html are fully-blown templates, written in xhtml and html respectively, and are targeted for non-handheld devices.
7.1 Note that cardid and cardtitle are deliberately incorrect here. fix_code.php corrects these later.
7.3 Detect
The main file is browser.php. This returns best suited $_SERVER["HTTP_ACCEPT"] and whether it is a hand-held device or not checking against $_SERVER["HTTP_USER_AGENT"]. This can be adapted to be a stand-alone script, but it has dependencies.
- $accept
- An array equivalent to the following, containing content-types.
The array key is straight forward, the array value is the full accept_type. This is used subsequently used in
$accept = array( "xhtml" => "application/xhtml+xml", "html" => "text/html", "wml" => "text/vnd.wap.wml", "mhtml" => "application/vnd.wap.xhtml+xml" );
drupal_set_html_head()anddrupal_set_header()respectively. - $browserlist
- This creates an array using
file()to openbrowser.inc. Contained inbrowser.incis a list of the first four characters of the user_agent string of known devices. Each device is listed on a new line. Extract below.alav alca armv au-m
Having created the 2 arrays listed above, the script now starts to check the $_SERVER["HTTP_ACCEPT"], including q value, so if the device accepts more than one mime type, the script should pick the best one. If there is no q value but $accept is there then 1 is added.
function media_type(&$accept, $browserfile, $mime = false) { $is_mobi = false; // note: this variable only exists within this function if ( $mime !== false ) { return $mime; } elseif (stristr($_SERVER["HTTP_USER_AGENT"],"W3C_Validator")) { return $mime = 'xhtml'; } elseif (!isset($_SERVER["HTTP_ACCEPT"])) { return $mime = 'html'; } else { $mime = 'html'; $c = array(); foreach ($accept AS $mime_lang => $mime_type) { $esc_type = '/'. str_replace( array ('/','.','+'), array('\/','\.','\+'), $mime_type) .";q=0(\.[1-9]+)/i"; $c[$mime_lang] = 1; if ( stristr($_SERVER["HTTP_ACCEPT"], $mime_type) ) { $c[$mime_lang] = $c[$mime_lang] + 1; } if (preg_match($esc_type, $_SERVER["HTTP_ACCEPT"],$matches)) { $c[$mime_lang] = $c[$mime_lang] - (float)$matches[1]; } $iMode = array('doco', 'j-pho', 'up.b', 'ddip', 'port'); if (in_array(strtolower(substr(trim($_SERVER['HTTP_USER_AGENT']),0,4)), $iMode)) { $mime = 'chtml'; $is_mobi = true; } else { arsort ($c, SORT_NUMERIC); /* The aim is to reduce $c to one element, the best suited accept_type */ if ( array_sum($c) == count($c) ) { unset ( $c ); $c['html'] = 1; } $max = max($c); foreach ($c as $type => $val) { if ($val != $max) unset ( $c[$type] ); } $browsers = file($browserfile); foreach ($browsers as $dev) $browserlist [] = trim($dev); if (in_array(strtolower(substr(trim($_SERVER['HTTP_USER_AGENT']),0,4)), $browserlist)) $is_mobi = 1; if ( array_key_exists('xhtml', $c) ) {unset ( $c ); $c['xhtml'] = 1;} if ( array_key_exists('html', $c) ) {unset ( $c ); $c['html'] = 1;} if ( array_key_exists('wml', $c) ) {unset ( $c ); $c['wml'] = 1;} if ( array_key_exists('mhtml', $c)) {unset ( $c ); $c['mhtml'] = 1;} $mime = key($c); } define ('MOBI', $is_mobi); return $mime; } }
application/vnd.wap.xhtml+xml and text/vnd.wap.wml added would be something follows if the code was debugged.
Array
(
[xhtml] => 2
[html] => 1.1
[wml] => 1.4
[mhtml] => 2
)For Firefox the final result should be xhtml and MOBI = false.
8. Configuration
fix_code.php is a file containing a similar function to html_fix(). It strips out all non-wml syntax using preg_replace and str_replace and is called when ob_start is called. Information about this file has been included here as it should be edited further to strip out any additional content that is not required.
Brief details on how to use these files were outlined here, additional information follows.
One site serving multiple devices using one code base
- Upload all files
- Log in as an administrator and enable all the uploaded templates
- Make the required changes to
common.inc - Amend the
settings.phpfile insites/defaultdirectory as detailed previously
Multisites using one code base
For more information on how to set up multisites with Drupal, please visit: instructions or overview.
- Upload all files
- Log in as an administrator and enable all the uploaded templates
- Make the required changes to
common.inc - Amend the
settings.phpfile insites/<b>device_name</b>directory specifying the$orto match the device of choice 8.1
8.1 The whole detection script does not need to be included in settings.php if the device type is know. Below is an example for WAP / WML site.
DEFINE ('DETECT_PATH', '/path/to/detect_directory/'); // change to suit $fixfile = DETECT_PATH .'fix_code.php'; drupal_set_header('Content-Type: text/vnd.wap.wml; charset=utf-8'); drupal_set_header('Vary: Accept'); $conf['default_nodes_main'] = 2; $conf['anonymous'] = 'Mobile User'; drupal_set_header('Content-Type: text/vnd.wap.wml, true'); include $fixfile; // extra file for stripping out non-wml syntax ob_start('fix_code'); $conf['theme_custom'] = 'wap'; // change to suit $conf['theme_default'] = 'wap'; // change to suit $output = '';
9. Summary
This article utilizes a simple device detection script and selects the relevant output. Further changes may be needed to strip out irrelevant content for mobile devices, most of which can be achieved by editing fix_code.php.
10. References and additional information
References and additional information.
Status
This document is draft. Development work has progressed to create a module to include this functionality. Files can be downloaded in zip format here.
References and Credits
- Serving up XHTML with the correct MIME type
- Sending XHTML as text/html Considered Harmful
- XHTML Media Types
- Web Developer Guide
- W3C Mobile Web Best Practices
- XHTML Mobile Profile 1.0
Comments
Send comments or queries here
Additional
Working example of this script can be seen at http://www.227net.com. Please note that due to limitation in sending XHTML with the correct content-type XHTML compatible browser still receive content as text/html. Multisites have also been enabled. Device dependant sites are listed below:
| Attachment | Size |
|---|---|
| files.zip | 4.78 KB |





Posted by thetoast 6 years ago
Just wanted to say I've been looking for a good website with resources for mobile development and this is by far the best. Thanks guys :
-) I'' be looking into this tutorial carefully as I am a drupal developer so hopefully I'll be able to give some feedback soon. Again, many thanks.
Drupal developer
Drupal developerPosted by awidarto 5 years ago
This is a great article i've been searching for days... Tried it but not workin on my Drupal5.1 installation, I know that this is only tested on 4.5 / 6 , but then what is the necessary tweak for 5.1 ?
Seems that the way 5.1 doing the bootstrap sequence is the problem ...
Thanks for great article anyway... :)
Posted by jabba_29 5 years ago
The module will be available for Drupal 5.1x very soon. New and improved for 4.7x too.
Working versions are available on sites mentioned above and 5.1x @ http://www.skiffie.com
Stay tuned..
---------------------------------------------------------------
- Let the might of your compassion arise to bring a quick end -
- to the flowing stream of the blood and tears ..... -
----------------------------------------------------------
Posted by jabba_29 5 years ago
The accessibility module can now be downloaded from the project pages: http://drupal.org/project/accessibility
Drupal 4.7 users can get the relevant files from my site: drupal accessibility module
Jamie
---------------------------------------------------------------
- Let the might of your compassion arise to bring a quick end -
- to the flowing stream of the blood and tears ..... -
----------------------------------------------------------
Posted by rahul2435 5 years ago
this is a gr8 script, but i was wondering if someone could clarify
something for me, im new to mobile content serving,
between practices and conventions,
this script does not seem to follow RFC 2616 Sec - 14
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
where in the script we are subtracting q value from 2, RFC says its the q value itself.
if we get
mhtml, xhtml;q=.8, wml;q=.5,
according to the RFC we should serve mhtml,
but checking with the script above we get
mhtml;q=2, xhtml;q=1.2, wml;q=1.5,
should we go by the RFC or the above is the normal followed practice.
Posted by jabba_29 5 years ago
if we get
mhtml, xhtml;q=.8, wml;q=.5,
according to the RFC we should serve mhtml,
but checking with the script above we get
mhtml;q=2, xhtml;q=1.2, wml;q=1.5,
should we go by the RFC or the above is the normal followed practice.
That means that the script should still use mhtml.
Adding 1 at the beginning was only meant to simplify the maths -
so there would be no negative numbers.
---------------------------------------------------------------
- Let the might of your compassion arise to bring a quick end -
- to the flowing stream of the blood and tears ..... -
----------------------------------------------------------
Posted by tripollr 5 years ago
Hi,
I'm quite new on Drupal, And after reading all this material I'm wondering about how to integrate more extended device detection capabilities based on a Device DB such as Wurfl. Thus, it would allow to format pages more suited to device characteristics (screen size, scripting languages, etc.).
Do anybody have any experience on this or can direct me to some suitable resources?
Kind regards,
Toni
Posted by MobilePublisher 5 years ago
Dear Toni / tripollr,
I've just finished writing a short-news in the m-zine MobilePublisher about the new version 6.0 of Drupal. MobilePublisher uses Drupal as well (in the background, as a CMS/CMF), just like you !
NOW --> Have you heard about dotMobi's DeviceAtlas? It is a NEW tool and DATABASE, which provides accurate information about attributes of mobile devices. The positive thing about it: It's free for members of the dev.mobi-developer-forum/community. I am checking/verifying DeviceAtlas at the moment, that's why I cannot give you any further information. I hope this was useful!
Best regards,
Philipp Schaffner
Posted by tripoll 5 years ago
Hi Philipp,
Thanks for your hints, although my german knowlegdge is too bad to read your short-news.
In any case I've been looking for information about MobilePublisher and I'm going to intall and try it.
Also, I've would test DeviceAtlas in order to check its usefulness, specially regarding elder devices which are still being used by people. Any valorations from other people would be welcome.
Regards,
Toni Ripoll
Toni Ripoll ADSMEDIA CTOADSMEDIA CTO
Posted by majorsoft 4 years ago
Hi All,
sorry about the cross posts.. trying to make sure i speak to the right poeple...
I have a weekend project to enable a web site to support downloading of j2me files.
I had a joomla developer doing this for me but he has ‘walked’ and now I urgently need to set this up.
I was thinking Joomla 1.5 but happy to take advice.
I want to be able to make available about 15 [or more] separate j2me programs – each one has 10 versions depending on phone screen size.
I want to be able to enable the user to select a file they want – then add their phone number to then push/send an SMS with the link to the users phone.
The user opens the link which takes them to a download page where the device type is detected and based on the screen size – the user is provided a download link.
It is a bit like a shopping cart – but delivery is via SMS link.
Is Joomla the best CMS to use?
Has anyone done this with SMS?
Is there a turnkey solution for mobile deployment of content?
Would anyone be prepared to assist me?
I have read the various articles on this excellent site – I just need some hand holding / good advice / assistance.
Thx all.
Major
Posted by tom@mobiledrupal.com 4 years ago
Hi,
I’ve recently started a blog, mobiledrupal.com, which all about making and testing mobile websites with Drupal. I’ve also added a section which summarises mobile modules available for Drupal, which I hope people will find helpul.
Please have a look and get in touch with any comments!
Tom