Installation profiles

Hello boys and girls :) We want to tell you a story about creating Drupal 7 Installation profiles. Imagine that you have some site features that you often use in your new projects or you wish to provide your client, friend or dog with an installer that will build a 'ready-to-go' website. So install of a profile could be a good solution. For example, you often need a typical corporate site with a news page, catalog, about us page. Let's start and do it.

Profiles in Drupal 7 are similar to modules. We are going to create a profile ComProfile, so let's create a 'comprofile' folder in Drupal profiles folder. There are two required files: comprofile.info and comprofile.profile. As for the .install file - it’s optional.

In our comprofile.info we define profile name, description, and module to enable. Note, that dependances will not only require these modules to exist, but also to be installed during the process.

comprofile.info

name = Corporate Site Profile
description = Description of what the profile does.
core = 7.x

dependencies[] = block
dependencies[] = color
dependencies[] = comment
dependencies[] = contextual
dependencies[] = dashboard
dependencies[] = views
...
Drupal profile selection
Drupal profile selection
Drupal modules installation
Drupal modules installation

.profile file allows us to add new steps with hook_install_tasks(). In our example we want to add a new installation step with our news and gallery features select. So a user can make a decision about what features he needs.

So let’s add our step:

/**
  * Implements hook_install_tasks(&$install_state).
  * 
  * @param array $install_state: An array of information about the current installation state.
  *
  * 'display_name': step name, visible for user. NOTE: function t() is not yet avaliable on install process, so you should use st() instead.
  *
  * 'display': TRUE or FALSE. In case of no display_name or FALSE value, step will be hidden from steps list.
  *
  * 'type': There are 3 values possible:
  * - "Normal" could return HTML content or NULL if step completed. Set to default.
  * - "Batch" means that the step should be executed via Batch API.
  * - "Form" is used when the step requires to be presented as a form. We used Form in our example, because we need to receive some info from user.
  *
  * 'run': Can be INSTALL_TASK_RUN_IF_REACHED, INSTALL_TASK_RUN_IF_NOT_COMPLETED or INSTALL_TASK_SKIP.
  * - INSTALL_TASK_RUN_IF_REACHED - means that the task should be executed on each step oo the install process. Mostly used by core functions.
  * - INSTALL_TASK_RUN_IF_NOT_COMPLETED - run task once during install. Set to default.
  * - INSTALL_TASK_SKIP - skip task. Can be useful, if previous steps info tells us that the task not needed and should be skipped.function - a function to execute when step is reached. If not set, machine_name function will be called.
  */

function comprofile_install_tasks($install_state) {
  $tasks['comprofile_config'] = array(
    'display_name' => st('ComProfile Config'),
    'display' => TRUE,
    'type' => 'form',
    'run' => INSTALL_TASK_RUN_IF_NOT_COMPLETED,
    'function' => 'comprofile_config_form',
  );
  return $tasks;
}

Now we can add our form with features select. We’ll create features modules later.

/**
  * Our custom form step.
  * Allow user to select profile features and demo content.
  * @param type $form_state
  * @return type
  */

function comprofile_config_form($form_state) {
  $form['features'] = array(
    '#type' => 'fieldset',
    '#title' => st('What features do you need?'),
  );
  $form['features']['components'] = array(
    '#type' => 'checkboxes',
    '#options' => array(
      'news' => st('News'),
      'catalog' => st('Catalog'),
    ),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => st('Apply'),
  );
  return $form;
}


/**
  * Enable features modules depending on users' choice.
  * @param type $form
  * @param type $form_state
  */

function comprofile_config_form_submit($form, &$form_state) {
  $modules = array();
  $modules[] = 'comprofile_common'; //Enable profile common settings and content.

  $values = $form_state['values'];
  if ($values['components']['news']) {
    $modules[] = 'comprofile_news'; //Enable News feature
  }
  if ($values['components']['catalog']) {
    $modules[] = 'comprofile_catalog'; //Enable Catalog feature
  }
  module_enable($modules);
}
Drupal features selection
Drupal features selection

Ok, now we have our custom step with features to install select. We could also wish to set a custom title. To do it, just use form alter hook:

/**
  * Implements hook_form_FORM_ID_alter() for install_configure_form().
  *
  * Allows the profile to alter the site configuration form.
  */

function comprofile_form_install_configure_form_alter(&$form, $form_state) {
  // Pre-populate the site name with the server name.
  $form['site_information']['site_name']['#default_value'] = st('My Company Profile');
}
Drupal configuration
Drupal configuration

You may also need to change the existing steps. There is a hook_install_tasks_alter() function, which has two arguments &$tasks and $install_state. We don’t need to do changes in our example, so let's just skip it.

As for the comprofile.install file, we will not set all possible code we can use, I'll just give you some examples of what we can do there.

/** Implements hook_install().
  * Perform actions to set up the site for this profile.
  * @see system_install()
  */

function comprofile_install() {
  //Enable some custom theme.
  variable_set('theme_default', 'busy');
  theme_enable(array('busy'));
  
  // Create a default role for site administrators, with all available permissions assigned.
  $admin_role = new stdClass();
  $admin_role->name = 'administrator';
  $admin_role->weight = 2;
  user_role_save($admin_role);
  user_role_grant_permissions($admin_role->rid, array_keys(module_invoke_all('permission')));
  
  // Set this as the administrator role.
  variable_set('user_admin_role', $admin_role->rid);
  
  // Assign user 1 the "administrator" role.
  db_insert('users_roles')
    ->fields(array('uid' => 1, 'rid' => $admin_role->rid))
    ->execute();
}

So on hook_install you could prepare content types, fields, formats, set blocks, variables and so on. A lot of examples are available in default Standard profile standard_install().

Features module can become a good alternative to write all the code manually. We've already told about features modules to enable on our form defining the function. Now we are going to use Features module.

In the administration menu, we created new content types - News and Catalog item, built with views content types display and menu links. So the site functions now look how they should look like being installed on our profile. With Features, we can now export custom modules by exporting settings we need. On attached screenshots, you can see how it looks.

The Features module
The Features module
The Features module
The Features module

With Features module we also used:

  • Strongarm - Export system variables.
  • Features Extra - Additional functions for Features modules, usually asked as a dependency for other modules.
  • UUID Features Integration - integration with UUID module, which allows you to export nodes and taxonomy content.
  • Boxes - Blocks export.

Such pack of modules allows us to create custom modules without coding. Now we can add exported modules to our profile and these features will be installed together with our profile.

MORE ON THE TOPIC: Drupal 8 Installation Profiles

You might also like