Drupal 8: Switching Installation Profiles

  • henok_mikre

    Henok Mikre

Drupal install profiles help organize custom code in Drupal projects -- especially in large, single-site instances. In Drupal 7, custom modules used to live in sites/all/modules/custom while custom themes used to live in sites/all/themes/custom. In Drupal 8, custom modules typically live in modules/custom. In multi-site installations, custom modules would be in sites/<site-name>/themes/custom. When new developers join an existing project, one of the first things they would need to do is locate custom modules, themes, and libraries. For projects that use make files (in Drupal 7) or Composer (in Drupal 8), it is much easier to ignore core, modules, libraries, and themes directories inside web directory and to put all custom work inside a profile. But what if a site has already been created using the default standard profile? That is where profile switching may be necessary. There is already a contrib module called Profile Switcher, however, the D8 version still has some bugs that need to be resolved. Below are manual steps we can take to switch a profile.

Update Hook

If a site is already in production, it is easier to do the profile switch in two steps. The first step is to create the blank profile and use an update hook to configure it. Here is a possible update hook:

/**
 * Change installation profile.
 */
function mymodule_update_8001() {
  // Get current profile name.
  $old = \Drupal::installProfile();

  // Set new profile name.
  $new = 'myprofile';

  // Set profile name in core.extension configuration.
  $extension_config = \Drupal::configFactory()->getEditable('core.extension');
  $extension_config->set('profile', $new)
    ->save();

  // Clear cache.
  drupal_flush_all_caches();

  // Install new profile as a module and uninstall old one.
  \Drupal::service('module_installer')->install([$new]);
  \Drupal::service('module_installer')->uninstall([$old]);

  // Replace install profile in key_value db.
  $schema = \Drupal::keyValue('system.schema');
  $weight = 8000;
  if ($weight == $schema->get($old)) {
    $schema->delete($old);
  }
  $schema->set($new, $weight);

  // Crear cache again.
  drupal_flush_all_caches();

  // Remove old profile info from key_value table so it generates a new one.
  $db = \Drupal::database();
  $db->delete('key_value')
    ->condition('collection', 'state')
    ->condition('name', 'system.profile.files')
    ->execute();

  // Clear cache again.
  drupal_flush_all_caches();

  // Remove the old profile from core.extension config.
  $module_data = \Drupal::config('core.extension')->get('module');
  unset($module_data[$old]);
  $extensions = \Drupal::configFactory()->getEditable('core.extension');
  $extensions->set('module', $module_data)->save();
}

Deployment

The initial deployment with the above will active the new profile and remove the default standard profile. We would then move all the custom and contrib modules into the profile and deploy that. Since the production database would know to look inside the profile for any modules, all we would need to do after the deployment is clear the cache and perhaps restart the web server (or flush any internal and external cache). If any CSS or PHP references were hardcoded to a specific path, those pages would break. Therefore, it is important to use relative paths.

Resources