Drupal 7 First Look
上QQ阅读APP看书,第一时间看更新

Creating custom installation profiles

Installation profiles allow you to easily install Drupal with additional functionality included by default. For example, you can set up an installation profile to:

  • Automatically add additional users to your site
  • Add additional roles to your site
  • Set up permissions for default users
  • Add additional contributed modules to your site
  • Add additional themes to your site
  • Add default content to your site
  • Modify common settings to speed setup

As you can see, the options for installation profiles are nearly limitless in Drupal 7. This is especially true because installation profiles are essentially modules now, and you can do nearly anything you want to with a custom module in an installation profile.

If you are only maintaining a single site, you probably won't want to create an installation profile, but if you are setting up many new customer sites each month, you should definitely consider building a custom installation profile to set up a base site that you can then extend to meet each customer's specific needs.

Components of an installation profile

Let's start by looking at the files that make up an installation profile.

  • The .info file: The .info file names and describes the installation profile and gives compatibility information so the installer can verify that the correct minimum requirements for the profile have been met and set up the correct modules.
  • The .profile file: The .profile file allows you to modify the site configuration form so you can request additional information from the user performing the installation or set default values for the installation. This file is specified within the .info file.
  • The .install file: The .install file contains the code that should be run to set up the new site after the core Drupal installation has completed.

The .info file

Let's look at the contents of the .info file. In this example, we will look at the default profile that ships with Drupal. Let's look at the entire file and then break down each section independently.

; $Id: default.info,v 1.8 2009/11/10 17:27:54 webchick Exp $
name = Drupal
description = Create a Drupal site with the most commonly used features pre-installed.
version = VERSION
core = 7.x
dependencies[] = block
dependencies[] = color
dependencies[] = comment
dependencies[] = dashboard
dependencies[] = help
dependencies[] = image
dependencies[] = menu
dependencies[] = path
dependencies[] = taxonomy
dependencies[] = dblog
dependencies[] = search
dependencies[] = shortcut
dependencies[] = toolbar
dependencies[] = field_ui
dependencies[] = file
dependencies[] = rdf
files[] = default.profile

; Information added by drupal.org packaging script on 2009-11-21
version = "7.x-dev"
core = "7.x"
project = "drupal"
datestamp = "1258805146"

As you can see, the file uses a basic INI style format that provides information in a series of name-value pairs using the format:

name = value

Names that end with square brackets [] are treated as arrays when they are read. Any lines which start with a semi-colon are treated as comments and ignored when the file is read.

The first line in the file is used by the version control system to insert version information. If you create your own installation profile, you should replace this line with:

; $Id;

The next four lines identify the name of the profile, a description of the profile, the current version of the profile, and the version of core this profile is compatible with.

name = Drupal
description = Create a Drupal site with the most commonly used features pre-installed.
version = VERSION
core = 7.x

You should modify at least the name and description values for your installation profile if you are building a custom installation profile.

Note

The default installation profile sets the version variable based on the value generated by the packaging script. If you are not posting your profile to Drupal.org to share with other site administrators, you will need to maintain this value yourself.

The dependencies lines list all of the modules that must be enabled for the profile to install correctly. The Drupal installer will automatically enable these modules for you.

dependencies[] = block
dependencies[] = color
dependencies[] = comment
dependencies[] = dashboard
...

You can add or remove any additional modules that you will need to use your installation profile. If you are using a third-party module, make sure that it has been deployed to your site before the installation profile has been run.

The files variable defines any files that are needed to run the installation profile. Typically, this will just be your .profile file. However, you may also include additional files if the setup you do is very complex. To include additional files, simply add another files[] line with the name of the file you want to include, as shown below:

files[] = default.profile

The remainder of the file contains information included automatically by the Drupal packaging script. You do not need to add these to your file if you are building a custom installation profile.

The .profile file

The .profile file allows you to alter the installation and change which forms are presented to the user.

The following hooks can be added to your .profile file:

  • hook_profile_details: This hook allows you to define a language that will be used during the installation. If a language is set here, the user will be unable to set the language during the installation. In Drupal 6, you would also define the name and description for the profile. You don't need to do that anymore since the name and description are provided in the .info file. For more information on this hook see:

    http://api.drupal.org/api/function/example_profile_details/7.

  • hook_install_tasks: This hook allows you to define additional tasks that will be performed at the end of the installation process. Each task will be executed in the order they are defined. A task can be one of three types:
    • normal: The function will be run and can return either HTML to be displayed to the user or nothing if processing should continue without further user interaction.
    • form: The function will return a form definition using the standard Form API. The installer will present the form to the user and then submit the form to the function you define for processing.
    • batch: The function will return a batch definition, which will be run by the installer. For more information about batches, see:

    http://api.drupal.org/api/function/batch_set/7.

    For complete documentation on this hook see:

    http://api.drupal.org/api/function/hook_install_tasks/7.

  • hook_install_tasks_alter: This hook allows you to change, replace, or remove tasks that are to be run by the installation process. You can modify any of the tasks that will be run from the time the installation profile is selected until the installation completes. This is especially useful if you want to override functionality provided by the core installer. For more information on this hook, see:

    http://api.drupal.org/api/function/hook_install_tasks_alter/7.

  • hook_form_alter: This hook allows you to modify a form before it is displayed. This allows you to add or remove elements from the form or modify existing elements within the form. hook_form_alter is widely used within Drupal to make modifications to forms. For complete documentation, visit:

    http://api.drupal.org/api/function/hook_form_alter/7.

As with any Drupal hook, you will need to replace the word "hook" with the name of your profile so Drupal can correctly find the function. Therefore, if your profile is named drupal_rocks, your function that implements hook_profile_details should be named drupal_rocks_profile_details.

The .install file

The .install file is where you will perform most of your configuration and setup work after the installation has completed.

You only need to implement one function in this file, hook_install. If you have created custom modules, this is the same function that runs when the module is installed. Complete instructions for hook_install are available at:

http://api.drupal.org/api/function/hook_install/7.

Let's look at the standard.install file provided with Drupal to get an idea of what is possible. Rather than looking at the entire file at once, let's break it into sections. If you want to see the entire file, it is located in the profiles/standard directory of your Drupal installation.

File structure

The basic structure of the file looks like the following:

<?php
// $Id: default.install,v 1.18 2009/11/10 17:27:54 webchick Exp $

/**
 * Implement hook_install().
 *
 * Perform actions to set up the site for this profile.
 */
function default_install() {
  //Actual work happens here!
  ...
}

The file starts out with the opening PHP tag <?php. Then, the Id is again entered automatically by the version control system. If you are developing your own installation module, you should simply enter // $Id$. Do not enter all the remaining information; that will be generated automatically. Next, the file has a comment (the information starting with /** and ending with */) stating what the function does. This is good coding practice and helps other people to understand what you are trying to do. It can also help you understand your own code if it's been a little while since you wrote it. You may even want to include a summary of what the installation will do, and why, to remind yourself after you have been away from the code for a while.

After the comment comes the actual implementation of hook_install. Since this profile is named default, the function is called default_install. The logic of the function is then included and the function ends with a closing curly bracket. By convention, Drupal files do not include the optional closing PHP tag after all functions have been written, so the file ends there.

Block creation

Now, let's look at the actual logic being performed within the profile. The first section of code begins by defining several blocks which are then added to the default display.

// Enable some standard blocks.
  $values = array(
    array(
      'module' => 'system',
      'delta' => 'main',
      'theme' => 'garland',
      'status' => 1,
      'weight' => 0,
      'region' => 'content',
      'pages' => '',
      'cache' => -1,
    ),
    ...
    array(
      'module' => 'user',
      'delta' => 'new',
      'theme' => 'seven',
      'status' => 1,
      'weight' => 0,
      'region' => 'dashboard_sidebar',
      'pages' => '',
      'cache' => -1,
    ),
  );
  $query = db_insert('block')->fields(array('module', 'delta', 'theme', 'status', 'weight', 'region', 'pages', 'cache'));
  foreach ($values as $record) {
    $query->values($record);
  }
  $query->execute();

Each block is loaded into the $values array. Each module defines the name of the module, which defines the block as well as the delta or unique ID of the block within the module. The theme setting controls which theme the block should be active for and the status variable controls if the block is enabled (1) or disabled (2). The region variable controls where the block should be displayed within the page and weight controls the position within the region. The pages setting controls which pages the block should be shown on. In the case of the default installation profile, they are shown on all pages. If you want to only show the block on some pages, you should also include the visibility parameter. The cache setting controls whether or not the block can be cached to optimize performance. By default, all blocks are set to -1, which means do not cache. You can change this to a variety of values for fine-grained caching control. For a complete list of fields that can be set for a block and their possible values, see:

http://api.drupal.org/api/function/block_schema/7.

The next several lines set up a query to insert the blocks into the database using the new DBTNG layer and then execute the query to save all of the new blocks. We will review the DBTNG layer more in Chapter 6, so don't worry about the actual syntax too much for now.

Node type definition

The next section adds some default node types that editors can use to add content to the site.

  // Insert default user-defined node types into the database. For a complete
  // list of available node type attributes, refer to the node type API
  // documentation at: http://api.drupal.org/api/HEAD/function/hook_node_info.
  $types = array(
    array(
      'type' => 'page',
      'name' => st('Page'),
      'base' => 'node_content',
      'description' => st("Use <em>pages</em> for your static content, such as an 'About us' page."),
      'custom' => 1,
      'modified' => 1,
      'locked' => 0,
    ),
    array(
      'type' => 'article',
      'name' => st('Article'),
      'base' => 'node_content',
      'description' => st('Use <em>articles</em> for time-specific content like news, press releases or blog posts.'),
      'custom' => 1,
      'modified' => 1,
      'locked' => 0,
    ),
  );

  foreach ($types as $type) {
    $type = node_type_set_defaults($type);
    node_type_save($type);
  }

In this case, two node types are being added—a page node type and an article node type. The installation profile defines the type, name, and description for each node type. These are all fairly straightforward. However, note that the st() function is called to provide translations rather than t(). This is done because the install function is called during the install process and the full localization system may not be available yet. The profile also sets the base for the node type, which tells Drupal which module will control the functionality of the node. By setting custom to 1, the installation profile instructs Drupal that this node type should be treated as if it were created by a user and that it is not defined by a module. Setting locked to 0 indicates that the name of the content type can be modified by an administrator.

After basic information has been defined for each node type, the installation profile begins to save each type individually. Before saving the type, it calls node_type_set_defaults, which builds a type object and adds additional default information to it. The new node type is then saved with a call to node_type_save.

Additional default settings

The installation profile then uses the same technique of defining an array of information and then saving it to build RDF-mapping information for each type as well as taxonomies and fields. Because these substantially use the same techniques as creating blocks and node types, we will omit a line by line discussion of these.

Between setting up the RDF mappings and creating taxonomies, the installation profile sets the values of some variables in the database using the following lines:

  // Default page to not be promoted and have comments disabled.
  variable_set('node_options_page', array('status'));
  variable_set('comment_page', COMMENT_NODE_HIDDEN);

  // Don't display date and author information for page nodes by default.
  variable_set('node_submitted_page', FALSE);

  // Enable user picture support and set the default to a square thumbnail option.
  variable_set('user_pictures', '1');
  variable_set('user_picture_dimensions', '1024x1024');
  variable_set('user_picture_file_size', '800');
  variable_set('user_picture_style', 'thumbnail');

All of these lines use the variable_set function to change the value of the variables. You can get a list of all variables defined within Drupal using the Devel module (http://drupal.org/project/devel).

Setting up permissions and roles

Skipping down to the end of the file after all of the fields have been created, the installation profile sets some default permissions for the Anonymous and Authenticated roles using a call to user_role_grant_permissions.

  // Enable default permissions for system roles.
  user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access content', 'use text format 1'));
  user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('access content', 'access comments', 'post comments', 'post comments without approval', 'use text format 1'));

If you are creating your own installation profile, which activates additional modules, you may want to activate additional permissions for these users.

The installation profile also creates a new role for the administrator and sets some default permissions:

  // Create a default role for site administrators, with all available permissions assigned.
  $admin_role = new stdClass();
  $admin_role->name = 'administrator';
  user_role_save($admin_role);
  user_role_grant_permissions($admin_role->rid, array_keys(module_invoke_all('permission')));

The new role is set up by creating an object to store the role and then saving it with a call to user_role_save. The permissions are granted by first calling module_invoke_all('permission'). This loads all available permissions for all modules which have been enabled, thus giving the administrator role all available permissions.

To ensure that the administrator role stays up to date, the installation profile assigns the administrator role as the system admin role by updating the appropriate system variable.

  // Set this as the administrator role.
  variable_set('user_admin_role', $admin_role->rid);

Next the profile rebuilds the menu system to ensure the cache is fresh and that all modules which were installed are correctly updated:

  // Update the menu router information.
  menu_rebuild();

Theme configuration

Finally, the installation profile activates the Seven theme and sets it up for use as the administration theme.

  // Enable the admin theme.
  db_update('system')
    ->fields(array('status' => 1))
    ->condition('type', 'theme')
    ->condition('name', 'seven')
    ->execute();
  variable_set('admin_theme', 'seven');
  variable_set('node_admin_theme', '1');

To do this, it again executes a query using the new DBTNG syntax and then sets a couple of variables to finalize the installation. Don't worry about the syntax of the update query too much right now; we will definitely explore this in more detail in Chapter 7.

After the Seven theme has been installed, the installation profile ends and the installation continues. Remember, because the Drupal core has been installed and all of your modules have been activated, when the install function runs, there is a wide range of actions you can perform during this routine.