Subdomain Multisite Part 2

Web Developer

Subdomain Multisite Part 2

This is a continuation of exploring Drupal subdomain multisites. Part 1 is here.

ISSUES WE'VE HAD TO SOLVE SO FAR:

​​Sharing user accounts and roles

Getting user accounts and roles to share between subdomains is very important. We want users to experience a single sign on (SSO) solution and for the site to appear to be one site. Luckily, we have some great tools to support this that are used on drupal.org!

First we'll need the following modules:

  • bakery
  • role_export

Bakery manages the user accounts and sign ins for all the drupal.org subsites like groups.drupal.org so it is pretty well tested. 

To set up bakery, we put its settings in the global.settings.php file we created in part 1.

// Set bakery settings.
$parts = explode('.', $_SERVER['HTTP_HOST']);
$subdomain = '';
if (count($parts) < 2) { // This is for drush.
  drupal_set_message('Could not determine domain name. add --uri=http://mydomain.local to drush to specify your domain name.');
}
else {
  if (count($parts) > 2) {
    $subdomain = array_shift($parts);
  }
  $base = implode('.', $parts);

  if ($subdomain == 'accounts') {
    $conf['bakery_is_master'] = TRUE;
    $conf['bakery_slaves'] = array(
      'http://kb.' . $base . '/',
      'http://forum.' . $base . '/',
      'http://' . $base . '/',
    );
  }
  else {
    $conf['bakery_is_master'] = FALSE;
  }
  $cookie_domain = '.' . $base; // Set cookie domain for logins.
}

// Common bakery configuration
$conf['bakery_master'] = 'http://accounts.' . $base . '/';
$conf['bakery_key'] = 'PRIVATEKEYHERE';
$conf['bakery_domain'] = '.' . $base;
$conf['bakery_supported_fields'] = array(
  'name' => 'name',
  'mail' => 'mail',
  'status' => 0,
  'picture' => 0,
  'language' => 0,
  'signature' => 0,
);  

You can tweak this as needed but it will set up bakery for sandboxes, dev, test and production without any tweaks at all. So you can have forum.client.localhost and kb.client.localhost and they will still use bakery properly.

Next we'll need to set up the feature which contains the user fields and roles. Role export assigns a role id to each role and allows us to export each of the roles to a global feature. We define all the roles for the whole site and export them to a global feature placed in sites/all/modules. We typically name this client_user. We also put any user fields in this file as well. For example, field_firstname and field_lastname. Then we make sure this feature is enabled on all the sub sites. This is so that all the sites have roles with the same ids and same fields on the user object.

The reason this is important is that it allows us to transfer field and roles across all the sites with minimal effort. To do this, we need to patch bakery with the patch in https://drupal.org/node/556666#comment-7294616

This creates two new hooks for bakery. Those are hook_bakery_transmit and hook_bakery_receive. This sends and receives additional information between the subdomains. Here are the hooks we typically use and we put them in the global feature we created with all the user and role information.

/**
 * Implements hook_bakery_transmit().
 */
function featurename_bakery_transmit($edit, $account, $category) {
  $info = array();
  //  First populate with account values
  foreach($account as $key => $value) {
    if (substr($key, 0, 6) == 'field_') {
      $info[$key] = $value;
    }
  }
  // Then override with edit values.
  foreach ($edit as $key => $value) {
    if (substr($key, 0, 6) == 'field_') {
      $info[$key] = $value;
    }
  }
  // Save off roles as well. Because of role_export all sites will have the same role ids.
  if (isset($edit['roles'])) {
    $info['roles'] = array_filter($edit['roles']);
  }
  else {
    $info['roles'] = array_filer($account->roles);
  }
  return array('featurename' => $info);
}

 

/**
 * Implements hook_bakery_receive().
 */
function featurename_bakery_receive($account, $edit) {
  if (isset($edit['data']['featurename'])) {
    return user_save($account, $edit['data']['featurename']);
  }
}

That pretty much does it. Just make sure that bakery and your client_user feature is enabled on all of the subsites and user accounts and sessions will be transferred to each of the subsites automatically. You will still need to set permissions for each role on each of the subsites but since they have different modules, their permissions will be different so this makes sense. 

I'll write up the next section soon.

Featured image from http://www.flickr.com/photos/premnath/.

Related Posts

Breaking up the Monolithic Drupal Site with a Subdomain Multisite

Randall Knutson
Read more

Learning Drupal - Part 1.5 - A New Hope

David Hahn
Read more

Learning Drupal - Part 2

David Hahn
Read more

Drupal 8 Module Development, Part 3: Plugins

Ian Whitcomb
Read more

Drupal 8 Module Development, Part 2: Forms

Ian Whitcomb
Read more

Drupal 8 Module Development, Part 1: Getting Started

Ian Whitcomb
Read more