background image
HomeRecent PostsDrupalSearchTagsRSSContactAboutAccount
Eric.London's picture

In this tutorial I'll explain how to setup your Drupal site to be mobile friendly. Before you begin, it's helpful to consider the following: 1) which mobile devices to support; 2) using a different theme for mobile; 3) which hostnames will be used; 4) multi-site configuration options; and 5) any site alterations to simplify the mobile experience.

For my site, I decided on the following:
1) iPhones (to start)
2) Use a more clean theme for my mobile site: DevSeed's Singular
3) redirect mobile traffic to a new subdomain (mobile.ericlondon.com)
4) I was using sites/default for my blog, so hosting another hostname on the same filesystem was not an issue
5) I decided to remove some items in my primary navigation, and add some jQuery (accordion effect) to collapse node content on my front page.

I added the new DNS for my subdomain to point to the same IP address of my main site. In a standard Apache vhosts configuration, you can add a ServerAlias directive to ensure the mobile hostname is handled by the main site's vhost. For example:

<VirtualHost *:80>
  ServerName ericlondon.com
  ServerAlias mobile.ericlondon.com
  DocumentRoot /var/www/vhosts/ericlondon.com/httpdocs
</VirtualHost>

I installed and enabled the Singular theme in sites/all/theme/singular.

I added some mobile specific configurations in my settings.php file (sites/default/settings.php):

<?php
/**
* Mobile Theme Configuration
*/

// define mobile http host
define('MOBILE_HTTP_HOST', 'mobile.ericlondon.com');

// define mobile theme
define('MOBILE_THEME','singular');

// override custom theme for mobile site
if ($_SERVER['HTTP_HOST'] == MOBILE_HTTP_HOST) {
 
$GLOBALS['custom_theme'] = MOBILE_THEME;
}

// check for iPhone
$is_iphone = preg_match('/iphone/i', $_SERVER['HTTP_USER_AGENT']); 

// redirect to mobile theme
if ($is_iphone && $_SERVER['HTTP_HOST']!=MOBILE_HTTP_HOST) {
 
header('Location: http://' . MOBILE_HTTP_HOST . $_SERVER['REQUEST_URI']);
  die;
}
?>

Now, if someone visits my site using an iPhone, the user would be redirected to my specified mobile address, AND a new mobile theme would be used!

Mobile iPhone

In addition, I decided to make some alterations to my mobile theme to simplify the interface. I created a module and added a hook_preprocess_page() implementation:

<?php
function MYMODULE_preprocess_page(&$vars) {

 
// only process page variables if this is the mobile address
 
if ($_SERVER['HTTP_HOST'] != MOBILE_HTTP_HOST) {
    return;
  }

 
// define mobile javascript
  /*
  NOTE: this jQuery is very specific to my theme, and is just shown as an example.
  I looked into using jquery_ui's accordion library, but it would not work out of the box with the structure of my new mobile theme :(
  In an ideal situation, all jQuery would be put in separate include files
  */
 
$js = "
 
    // define node container
    var node_container = '.front #page #content';
     
    // define function to collapse node content
    function collapse_nodes() {     
      $(node_container + ' .node div').hide();
    }
 
    // define function to add click event
    function node_title_add_click() {
      $(node_container + ' .node h2.node-title a').click(function(){
        collapse_nodes();
        $('div', $(this).parent().parent()).show();
        return false;
      });
    }
   
    $(document).ready(function(){

      collapse_nodes();
      node_title_add_click();
     
    });
  "
;
 
drupal_add_js($js, 'inline');
 
 
// rebuild scripts variable
 
$vars['scripts'] = drupal_get_js();
 
 
// determine a list of hrefs to remove from primary navigation
 
$href_remove = array(
   
'drupal',
   
'tagadelic/chunk/1',
   
'recent-posts',
   
'rss.xml',
   
'logout',
   
'contact',
  );
 
 
// loop through primary links and remove as necessary
 
if (is_array($vars['primary_links'])) {
    foreach (
$vars['primary_links'] as $key => $value) {
      if (
in_array(strtolower($value['href']), $href_remove)) {
        unset(
$vars['primary_links'][$key]);
      }
    }
  }
 
}
?>

By added the above module code and jQuery, I removed some items from my primary navigation and added an accordion-like interface for the front page:

Mobile theme

NOTE: If you're using a Mac, the iPhone Simulator application (which comes with Xcode + iPhone SDK) is a great way to development and test mobile configurations.In this tutorial I'll explain how to setup your Drupal site to be mobile friendly. Before you begin, it's helpful to consider the following: 1) which mobile devices to support; 2) using a different theme for mobile; 3) which hostnames will be used; 4) multi-site configuration options; and 5) any site alterations to simplify the mobile experience.

For my site, I decided on the following:
1) iPhones (to start)
2) Use a more clean theme for my mobile site: DevSeed's Singular
3) redirect mobile traffic to a new subdomain (mobile.ericlondon.com)
4) I was using sites/ericlondon.com for my blog, so hosting another hostname on the same filesystem was not an issue
5) I decided to remove some items in my primary navigation, and add some jQuery (accordion effect) to collapse node content on my front page.

I added the new DNS for my subdomain to point to the same IP address of my main site. In a standard Apache vhosts configuration, you can add a ServerAlias directive to ensure the mobile hostname is handled by the main site's vhost. For example:

<VirtualHost *:80>
  ServerName ericlondon.com
  ServerAlias mobile.ericlondon.com
  DocumentRoot /var/www/vhosts/ericlondon.com/httpdocs
</VirtualHost>

I installed and enabled the Singular theme in sites/all/theme/singular.

I added some mobile specific configurations in my settings.php file (sites/ericlondon.com/settings.php):

<?php
/**
* Mobile Theme Configuration
*/

// define mobile http host
define('MOBILE_HTTP_HOST', 'mobile.ericlondon.com');

// define mobile theme
define('MOBILE_THEME','singular');

// override custom theme for mobile site
if ($_SERVER['HTTP_HOST'] == MOBILE_HTTP_HOST) {
 
$GLOBALS['custom_theme'] = MOBILE_THEME;
}

// check for iPhone
$is_iphone = preg_match('/iphone/i', $_SERVER['HTTP_USER_AGENT']); 

// redirect to mobile theme
if ($is_iphone && $_SERVER['HTTP_HOST']!=MOBILE_HTTP_HOST) {
 
header('Location: http://' . MOBILE_HTTP_HOST);
  die;
}
?>

Now, if someone visits my site using an iPhone, the user would be redirected to my specified mobile address, AND a new mobile theme would be used!

Mobile iPhone

In addition, I decided to make some alterations to my mobile theme to simplify the interface. I created a module and added a hook_preprocess_page() implementation:

<?php
function MYMODULE_preprocess_page(&$vars) {

 
// only process page variables if this is the mobile address
 
if ($_SERVER['HTTP_HOST'] != MOBILE_HTTP_HOST) {
    return;
  }

 
// define mobile javascript
  /*
  NOTE: this jQuery is very specific to my theme, and is just shown as an example.
  I looked into using jquery_ui's accordion library, but it would not work out of the box with the structure of my new mobile theme :(
  In an ideal situation, all jQuery would be put in separate include files
  */
 
$js = "
 
    // define node container
    var node_container = '.front #page #content';
     
    // define function to collapse node content
    function collapse_nodes() {     
      $(node_container + ' .node div').hide();
    }
 
    // define function to add click event
    function node_title_add_click() {
      $(node_container + ' .node h2.node-title a').click(function(){
        collapse_nodes();
        $('div', $(this).parent().parent()).show();
        return false;
      });
    }
   
    $(document).ready(function(){

      collapse_nodes();
      node_title_add_click();
     
    });
  "
;
 
drupal_add_js($js, 'inline');
 
 
// rebuild scripts variable
 
$vars['scripts'] = drupal_get_js();
 
 
// determine a list of hrefs to remove from primary navigation
 
$href_remove = array(
   
'drupal',
   
'tagadelic/chunk/1',
   
'recent-posts',
   
'rss.xml',
   
'logout',
   
'contact',
  );
 
 
// loop through primary links and remove as necessary
 
if (is_array($vars['primary_links'])) {
    foreach (
$vars['primary_links'] as $key => $value) {
      if (
in_array(strtolower($value['href']), $href_remove)) {
        unset(
$vars['primary_links'][$key]);
      }
    }
  }
 
}
?>

By added the above module code and jQuery, I removed some items from my primary navigation and added an accordion-like interface for the front page:

Mobile theme

NOTE: If you're using a Mac, the iPhone Simulator application (which comes with Xcode + iPhone SDK) is a great way to development and test mobile configurations.

In this blog entry, I'll explain how I setup a multi-site Drupal 6 installation with shared databases and single sign-on. This will enable you to store your users (and other desired tables) in a separate database, and share them across multiple sites.

Before installing Drupal I created 3 databases, added 2 mysql users, and granted permissions. Both mysql users will have access to the shared database which will contain the shared tables:

$ mysql
# create new databases:
mysql> create database drupal_ms_1;
mysql> create database drupal_ms_2;
mysql> create database drupal_ms_shared;

# create new user "drupal_ms_1" and grant privileges to the databases:
mysql> grant all privileges on drupal_ms_1.* to 'drupal_ms_1'@'localhost' identified by 'drupal_ms_1';
mysql> grant all privileges on drupal_ms_shared.* to 'drupal_ms_1'@'localhost' identified by 'drupal_ms_1';

# create new user "drupal_ms_2" and grant privileges to the databases:
mysql> grant all privileges on drupal_ms_2.* to 'drupal_ms_2'@'localhost' identified by 'drupal_ms_2';
mysql> grant all privileges on drupal_ms_shared.* to 'drupal_ms_2'@'localhost' identified by 'drupal_ms_2';

For my setup I wanted to use a single Drupal filesystem, so I created a name-based Apache virtualhost to host both domain names (ms1.erl.dev & ms2.erl.dev):

NameVirtualHost *:80

<VirtualHost *:80>
ServerName ms1.erl.dev
ServerAlias ms2.erl.dev
DocumentRoot /var/www/vhosts/ms.erl.dev/httpdocs
ErrorLog logs/ms.erl.dev-error_log
CustomLog logs/ms.erl.dev-access_log common
</VirtualHost>

I downloaded and unpacked the Drupal installation file:

$ cd /var/www/vhosts
$ mkdir ms.erl.dev
$ cd ms.erl.dev
$ wget http://ftp.drupal.org/files/projects/drupal-6.13.tar.gz
$ tar -xzf drupal-6.13.tar.gz
$ mv drupal-6.13 httpdocs

I setup 2 new sites folders in the sites folder, and copied the default.settings.php file into my first site:

$ cd httpdocs/sites
$ mkdir ms1.erl.dev
$ mkdir ms2.erl.dev
$ cp default/default.settings.php ms1.erl.dev

At this point my databases and filesystem were ready to go so I installed Drupal for the first site (ms1.erl.dev). During installation, I entered "localhost" for the database host, drupal_ms_1 as the database, and drupal_ms_1 as the database user. I left the db_prefix setting blank (we'll change that later).

Now that Drupal was installed and the tables were created, it was time to modify the installation to enable single sign-on and shared databases.

You'll need to decide which tables to share across the sites. I decided on users, sessions, and authmap (but you could add more as desired, like roles, profile_*, etc). I used the following commands to transfer the desired tables from the drupal_ms_1 database into the shared database, remove the tables from drupal_ms_1, and then replicated drupal_ms_1 to drupal_ms_2:

$ mysqldump drupal_ms_1 users sessions authmap | mysql drupal_ms_shared
$ mysql drupal_ms_1
mysql> drop table authmap, sessions, users;
mysql> exit
$ mysqldump drupal_ms_1 | mysql drupal_ms_2

Next, I modified the settings.php for my first site (sites/ms1.erl.dev/settings.php) to enable the shared database and single sign-on configuration. The $db_prefix variable is used to specify a different database using the [DATABASE].[TABLE] syntax. You'll also need to add the $cookie_domain variable to ensure the cookie set by Drupal will work across both domain names.

<?php
// Replace:
$db_prefix = '';
// With:
$db_prefix = array(
 
'default' => '',
 
'users' => 'drupal_ms_shared.',
 
'sessions' => 'drupal_ms_shared.',
 
'authmap' => 'drupal_ms_shared.'
);
// Add:
$cookie_domain = '.erl.dev';
?>

I then copied the ms1.erl.dev settings.php file into my second sites folder. Edit the new ms2.erl.dev/settings.php $db_url variable to point to the drupal_ms_2 database (and update the user and password as well).

$ cp ms1.erl.dev/settings.php ms2.erl.dev

After you delete your domain cookies everything should be working! To test this out, log into your first site and then open a new window/tab and go to your second site. You should be logged in as the same user. If you log out from one site, you should also be logged out from the other site.

If you're running a multi-site Drupal configuration, it's helpful to know which settings.php is being loaded. This information may be useful to your module or theme, or for troubleshooting purposes. For instance, you might be sharing the same theme across a few sites, but you'd like to modify the theme for one of your sites. Sharing themes (and modules) is capable in a multi-site configuration by placing your themes and modules in the [sites/all] folder, while defining a directory and settings.php file for each site installation in [sites]. To be able to tell which settings.php is being loaded, you could add the following code to each settings.php file you define:

<?php
$exploded
= explode("/", __FILE__);
$conf['multi_site_hostname'] = $exploded[count($exploded)-2];
?>

For example, you could pass this information to your page.tpl theme file:

<?php
// defining a preprocess_page function, placed in my template.php file:
function MYTHEME_preprocess_page(&$variables) {
 
// example: pass the configuration directly to the page.tpl.php:
 
$variables['multi_site_hostname'] = variable_get('multi_site_hostname',NULL);

 
// another example:
 
switch (variable_get('multi_site_hostname',NULL)) {
    case
'thedrupalblog.erl.dev':
    case
'ericlondon.com':
     
$variables['siteHostName'] = 'ericlondon.com';
      break;
    default:
     
$variables['siteHostName'] = 'default';
      break;
  }

}
?>

Syndicate content