Create a low bandwidth version of your site using the Context module.

Sep
22

In this article I would like to talk about creating low bandwidth versions of websites running on Drupal 6.x.

The times of dial-up and other types of slow internet connections are (almost) over, but sometimes it's still important to give your users the option to experience a light version of your website. I will explain how to implement such functionality using the context module. This will also serve as a good example of how to write context conditions.

The idea is pretty simple; If a user clicks on a 'Low bandwidth version' link, we hide some “heavy” blocks on the site. As the context module can hide and show blocks, we only need to implement a condition and use it to switch between versions of the site.

A technical aspect of this implementation is that we can keep information about the version of the site that the user requested via cookies, $_GET variable or HTTP headers (E.g. setting a header flag based on a cookie in a load balancer). This was suggested by my colleague Fabian Franz, who I would like to thank for this great idea.

The reason why we do not simply use $_SESSION to store the context is because we would like to use Varnish(reverse proxy web server). We want to keep anonymous users served from the varnish cache and reverse proxies do not support use of the $_SESSION variable. I.e. Pages will be generated by Drupal and served by Apache/lighttpd/nginx.

Let's start by writing the condition for the context module. The context module is extensible via plugins, so first we need to tell it where to look for our plugin.

<?php
/**
* Implementation of hook_context_plugins().
*/
function context_bandwidth_context_plugins() {
 
$plugins = array();

  $plugins['context_bandwidth_condition'] = array(
   
'handler' => array(
     
'path' => drupal_get_path('module', 'context_bandwidth') . '/plugins',
     
'file' => 'context_bandwidth_condition.inc',
     
'class' => 'context_bandwidth_condition',
     
'parent' => 'context_condition',
    ),
  );

  return $plugins;
}
?>

Next, we need to register our plugin so that it is a condition plugin.

<?php
/**
* Implementation of hook_context_registry().
*/
function context_bandwidth_context_registry() {
  return array(
   
'conditions' => array(
     
'context_bandwidth_condition' => array(
       
'title' => t('Bandwidth'),
       
'description' => t('Used for low bandwidth version of the site.'),
       
'plugin' => 'context_bandwidth_condition',
      ),
    ),
  );
}
?>

Next, we define when we “execute the plugin”. This is the tricky part, but the idea is that during code execution, we need to check whether the condition of our plugin is met or not. Since we need to know what site version to show as early as possible, we execute on hook_init().

<?php
/*
* Implementation of hook_init().
*/
function context_bandwidth_init() {
 
// Set context.
 
if ($plugin = context_get_plugin('condition', 'context_bandwidth_condition')) {
   
$plugin->execute('all');
  }
}
?>

Now let's look at the plugin code. This is in the file includes/context_bandwidth_condition.inc.

The tricky part is that the plugin method condition_values() should always return something, otherwise the condition won't be saved.

In the options form we let the user choose when the condition will be met; I.e. Whether the site is showing the Low Bandwidth or High Bandwidth version. This will look like the following:

The last part is execution. We check what the settings of the condition are and run $this->condition_met($context) if the condition is satisfied.

<?php
/**
* Check whether current site should be Low bandwidth version.
*/
class context_bandwidth_condition extends context_condition {
  function
condition_values() {
    return array(
       
1 => t('Active condition')
    );
  }

  function options_form($context) {
   
$defaults = $this->fetch_from_context($context, 'options');
    return array(
     
'mode' => array(
       
'#title' => t('Active for'),
       
'#type' => 'select',
       
'#options' => array(
         
'low' => t('Low Bandwidth version of the site'),
         
'high' => t('High Bandwidth version of the site'),
        ),
       
'#default_value' => isset($defaults['mode']) ? $defaults['mode'] : 'low',
      ),
    );
  }

  function execute($value) {
    if (
$this->condition_used()) {
     
// Check if current site is Low Bandwidth.
     
$condition = context_bandwidth_is_lowbw_version();

      foreach ($this->get_contexts() as $context) {
       
// Get the setting whether we should react on
        // Low or High bandwidth site version.
       
$options = $this->fetch_from_context($context, 'options');
       
$mode = !empty($options['mode']) ? $options['mode'] : 'low';

        if (($condition && $mode == 'low') || (!$condition && $mode == 'high')) {
         
$this->condition_met($context);
        }
      }
    }
  }
}
?>

The function context_bandwidth_is_lowbw_version() checks the current version of the site in the following way:

<?php
/**
* Get current site version.
*
* @return boolean
*   TRUE if current site is Low Bandwidth version.
*/
function context_bandwidth_is_lowbw_version() {
  return (
         (isset(
$_COOKIE["low_bandwidth"]) && $_COOKIE["low_bandwidth"] == 1)
      || (isset(
$_GET["low_bandwidth"]) && $_GET["low_bandwidth"] == 1)
      || (isset(
$_SERVER["X-Use-LowBandwidth"]) && $_SERVER["X-Use-LowBandwidth"] == 1));
}
?>

Another remaining issue that we have to solve is how to implement the “switcher.” For this we will create a block.

In order to set the cookie we will use the jQuery cookie plugin (included in http://drupal.org/project/jquery_plugin). In our code we export the settings of the cookie.

<?php
/**
* Implementation of hook_block().
*/
function context_bandwidth_block($op = 'list', $delta = 0, $edit = array()) {
  switch (
$op) {
    case
'list':
     
$blocks['context_bandwidth_link'] = array(
       
'info' => t('Bandwidth version switcher'),
      );
      return
$blocks;
      break;
    case
'view':
     
$block = array();
      switch(
$delta) {
        case
'context_bandwidth_link':
         
$site_version = context_bandwidth_is_lowbw_version();

          // Init cookies settings.
         
$cookie_path = ini_get('session.cookie_path');
         
$expires = ini_get('session.cookie_lifetime');
         
$expires = (!empty($expires) && is_numeric($expires)) ? time() + (int)$expires : 0;

          $settings = array(
           
'cookie_info' => array(
             
'name' => 'low_bandwidth',
             
'value' => $site_version ? 0 : 1,
             
'options' => array(
               
'path' => $cookie_path,
               
'domain' => ini_get('session.cookie_domain'),
               
'secure' => false, //(ini_get('session.cookie_secure') == '1')
             
),
             
'expires' => $expires,
            )
          );

          // Add javascripts and js settings.
         
jquery_plugin_add('cookie');
         
drupal_add_js(drupal_get_path('module', 'context_bandwidth') . '/context_bandwidth.js');
         
drupal_add_js(array('context_bandwidth' => $settings), 'setting');

          $link_title = $site_version ? t('High bandwidth') : t('Low bandwidth');

          // Prepare settings for the link.
         
$query = $_GET;
          unset(
$query['q']);
         
$current_path = $_GET['q'];

          unset($query['low_bandwidth']);
          if (!
$site_version) {
           
$query['low_bandwidth'] = 1;
          }

          $block = array(
           
'content' => theme('context_bandwidth_block_switcher', $link_title, $current_path, $query),
          );
          break;
      }
      return
$block;
  }
}
?>

The javascript shipped with our module just sets the cookie from settings when the switcher link is clicked. The method outlined above is also a great method to retrieve any cookies set via javascript from Drupal. This is useful for example when Varnish filters out the cookies to be set like described in our recent Boosted Varnish article.

An alternative to using cookies for saving the state, is using the Persistent URL module. In that case the url would not change for the normal site, but be prefixed with for example /light/ for the low bandwidth version of the site.

You are welcome to test the code of the module and give some feedback. I have attached the code at the bottom of this post (Download). I will greatly appreciate any comments.

Thanks for reading.

AttachmentSize
context_bandwidth.tar.gz2.13 KB

1 Comment

These ways that you have

These ways that you have shared on how to create a low bandwidth version is really great. I am not into IT but I easily understand those tips that you have discussed above. The codes are not that hard too to remember and followed. The method also that been outlined above is also great method to retrieve any cookies set via javascript from Drupal.. Thank you for sharing.

Richel

Blog: aspirateur à main 

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.

More information about formatting options