Last updated October 20, 2013. Created by IceCreamYou on January 10, 2011.
Edited by davidneedham, technicalknockout, kiamlaluno, klausi. Log in to edit this page.

Based on this article.

Installation profiles are like modules

All installation profiles must have profilename.info and profilename.profile files, and they can also have a profilename.install file. The profilename.profile file has access to almost everything a normal Drupal modulename.module file does because Drupal is fully bootstrapped before almost anything in the profile runs. The primary exception is that st() should generally be used to translate strings instead of the usual t() because the localization hasn't been set up until the installation process completes. Profile files should reside in their own directory within the /profiles directory to be loaded.

.info file

The profilename.info file should look similar to this:

name = Profile Name
description = Description of what the profile does.
core = 7.x
dependencies[] = block
dependencies[] = color
dependencies[] = comment
dependencies[] = contextual
dependencies[] = dashboard
dependencies[] = help
dependencies[] = image
dependencies[] = list
dependencies[] = menu
dependencies[] = number
dependencies[] = options
dependencies[] = path
dependencies[] = taxonomy
dependencies[] = dblog
dependencies[] = search
dependencies[] = shortcut
dependencies[] = toolbar
dependencies[] = overlay
dependencies[] = field_ui
dependencies[] = file
dependencies[] = rdf

The contents of the profilename.info file are as follows:
  • The name, description, and core assignments are all required.
  • The dependencies list includes all modules that will be enabled when this profile is installed (the ones above are the defaults from the Standard install profile).
  • You can optionally include other declarations that can also appear in module .info files.

You can include custom modules with your install profile or have Drupal.org automatically include other projects in your profile's package, and you can list those as dependencies as well.

.install file

In many cases, your profilename.install file will look like this:

<?php
/**
* Implement hook_install().
*
* Perform actions to set up the site for this profile.
*/
function profilename_install() {
  include_once
DRUPAL_ROOT . '/profiles/minimal/minimal.install';
 
minimal_install();
}
?>

Use hook_install() to insert content into your database during the installation process. This example uses the minimal default setup given by the Minimal install profile in Drupal core. You may want to use the Standard profile defaults instead, which provides various node types, user roles, blocks, input formats, taxonomies, settings, etc. that you might expect to find in a Drupal installation. If you don't use the Standard installation, it's still worth taking a look at it as an example.

Updating installation profiles

Just like modules, installation profiles can have hook_update_N() functions in their .install file so that they can be updated to the latest version. For example, if you release version 1.0 of your install profile that installs one content type, and then you release version 2.0 that installs two content types, version 2.0 could have an update function that installed the second content type for sites that had originally used the 1.0 version.

.profile file

The rest of this page explains what you can do in profilename.profile.

Adding steps to the install process

New steps added to the installation process can either run invisibly in the background (normally to save data or include code needed in later steps) or display something on the screen. New steps are added in hook_install_tasks() by returning an associative array. Here's what each task array looks like (all elements are optional):

<?php
$task
['machine_name'] = array(
 
'display_name' => st('Human-readable task name'),
 
'display' => TRUE,
 
'type' => 'normal',
 
'run' => INSTALL_TASK_RUN_IF_REACHED,
 
'function' => 'function_to_execute',
);
?>

Let's break it down.

machine_name
The internal name of the task.
display_name
The human-readable name of the task.
display
Determines whether to show this task in the list of installation tasks on the side of the installation screens. If display_name is not given or display is FALSE, the task does not appear in the list of installation tasks on the side of the installation screens. display is useful if you want to conditionally display a task; for example, you might want to display a configuration form for a module that the user chose to enable in a previous step, but skip that form if the module was not enabled.
type
One of "normal," "batch," or "form."
  • "Normal" tasks can return HTML that will be displayed as a page in the installer or NULL to indicate that the task is completed. This is the default. Remember to provide some way to continue to the next step, such as a "continue" button.
  • "Batch" tasks return a batch array to be processed by the Batch API, which is useful for example if you want to import something that could take awhile. The task will be considered complete when the batch finishes processing.
  • "Form" tasks return a Form API structured array which will be displayed as a form on a page in the installer. The installer will take care of moving the user to the next task when the form is submitted.

You can see more specifically what happens for each type in install_run_task().

run
One of INSTALL_TASK_RUN_IF_REACHED, INSTALL_TASK_RUN_IF_NOT_COMPLETED, or INSTALL_TASK_SKIP.
  • INSTALL_TASK_RUN_IF_REACHED means the task will run at each stage of the installation that reaches it. This is mainly used by core to include important resources on each page of the installer.
  • INSTALL_TASK_RUN_IF_NOT_COMPLETED means the task will run once during the installation process. This is the default, and it is useful for things like displaying instructions and configuration forms, or for inserting content into the database.
  • INSTALL_TASK_SKIP means the task will not be run. This is usually set conditionally, since you may want to skip tasks depending on the options the user chose in previous steps. It is often the case that a task will be skipped when display is set to FALSE, but it is possible to display a task in the list without executing it.
function
This is the function that will be run when the task is executed. If not set, this is the same as the machine_name of the task. You may want to set it to something else if you want to use the same function for multiple tasks, or if you want to conditionally choose a function depending on the options the user chose in previous steps.

As an example, let's say we're writing an installation profile called geo for a geographically-focused website, so we want the installer to ask what geographic area the website covers. We'll start by adding a page that asks for the relevant country. If the country is "United States," we'll add another page that asks for the relevant state, or if the country is "Canada," we'll add another page that asks for the relevant province.

<?php
/**
* Implements hook_install_tasks().
*/
function geo_install_tasks($install_state) {
 
$country_is_us = !empty($install_state['parameters']['country']) && $install_state['parameters']['country'] == 'US';
 
$country_is_ca = !empty($install_state['parameters']['country']) && $install_state['parameters']['country'] == 'CA';
 
$tasks = array(
   
'geo_country' => array(
     
'display_name' => st('Choose a country'),
    ),
   
'geo_state' => array(
     
'display_name' => st('Choose a state or province'),
     
'display' => $country_is_us || $country_is_ca,
     
'type' => 'form',
     
'run' => $country_is_us || $country_is_ca ? INSTALL_TASK_RUN_IF_NOT_COMPLETED : INSTALL_TASK_SKIP,
     
'function' => $country_is_us ? 'geo_state_form' : 'geo_province_form',
    ),
  );
  return
$tasks;
}
?>

For the geo_country task above, "Choose a country" is displayed in the list of tasks in the installer, and the function geo_country() is run when the installer reaches that task. Since it has type "normal," it must do its own processing, calling a form using drupal_get_form() and then rendering it by returning the results of drupal_render(). (See install_select_locale() for an example of this.) The form's submit function would set $install_state['parameters']['country'] appropriately. Then, if the country chosen is the U.S. or Canada, "Choose a state or province" is displayed in the installer, and either geo_state_form() or geo_province_form() is used to generate the state- or province-selection form.

All tasks added in hook_install_tasks() are run after all dependencies are installed and loaded, so you have access to pretty much everything you would in a normal Drupal module.

Changing and removing steps from the install process

hook_install_tasks_alter() allows changing or removing steps from the install process. For example, if you are building an install profile specifically for sites using a certain language, you might want to remove the localization steps and simply configure the language settings yourself.

hook_install_tasks_alter() takes two parameters: &$tasks and $install_state. The $tasks variable contains a structured array of all installation tasks like the one you returned in hook_install_tasks(). Here are the default tasks, in order, as defined by install_tasks():

install_select_profile
A configuration page to select which profile to install. It doesn't make any sense to change this, because by the time your profile gets control, it will have already been chosen.
install_select_locale
Allows choosing the language to use in the installer.
install_load_profile
Loads the selected profile into memory.
install_verify_requirements
Checks whether the current server meets the correct requirements for installing Drupal.
install_settings_form
The form used to configure and rewrite settings.php.
install_system_module
Installs the system module so that the system can be bootstrapped, and installs the user module so that sessions can be recorded during bootstrap.
install_bootstrap_full
Does a full bootstrap of Drupal, loading all core functions and resources.
install_profile_modules
Installs and enables all modules on which the profile depends (as defined in the .info file), and then runs profilename_install() if it exists (as defined in the .install file).
install_import_locales
Import available languages into the system.
install_configure_form
A form to configure site information and settings.
Profile tasks
Now any tasks defined by the current installation profile are run. Drupal has already been fully bootstrapped, all required modules are already installed and enabled, and the profile itself has also been "installed," so each task should have access to anything a normal Drupal module would be able to access.
install_import_locales_remaining
Imports additional languages into the system if any have not yet been imported.
install_finished
Performs final installation tasks (like clearing caches) and informs the user that the installation process is complete.

Altering forms

You can also alter forms displayed by the installer using hook_form_alter() and hook_form_FORM_ID_alter() just like you would alter forms in a normal module. The form IDs are the machine names of the tasks by default. You may want to do this to add additional fields to the install_configure_form step, for example. Most installation profiles will also want to include this snippet, which sets the default site name to the name of the server:

<?php
/**
* Implements hook_form_FORM_ID_alter().
*/
function standard_form_install_configure_form_alter(&$form, $form_state) {
 
// Pre-populate the site name with the server name.
 
$form['site_information']['site_name']['#default_value'] = $_SERVER['SERVER_NAME'];
}
?>

Inserting content into the database, and other useful functions

  • variable_set() and variable_get() are particularly useful to remember what your install tasks have already done. Just remember to use variable_del() to delete any temporary variables you've created when you're done.
  • If you need more fine-grained control than the dependencies[] in the .info file can give you, you may want to use module_enable() to enable a specific module during the install process. Enabling themes is similar, but setting the default, admin, and maintenance themes requires a little extra work.
  • drupal_set_title() allows you to set the title of the page as it appears at the top of the browser window.
  • Check the standard_install() function for examples of how to save various kinds of content in the database, including content types, taxonomies, user roles and permissions, input formats, fields, menu links, and RDF mappings.

Final notes

Be sure to check out how to create a drupal-org.make file if you want to distribute your profile on Drupal.org.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

Can we have a module instead for this please (for creating profiles)? Perhaps an extension for Features:
http://www.drupal.org/project/features

Do installation profiles have to live in the /profiles directory, or can you put them somewhere outside of core, such as sites?

It has to live in the /profiles directory, otherwise its not seen and cannot be loaded.

I check it daily just to see if any new stuff comes up. I have many issues clear in my head, but unfortunately they seem to arise just as many points of confusion. I am trying to build and installation profile built to use on my Aegir system...and man, it is killing me.

Things like:

- Supposing I am not distributing this install profile (or distribution) in Drupal, just for in-house use....Do I need to include a drush make file? If I have to, does Drupal 7 automatically sees it and uses it?

- I understand that we should move any and all customization to Features. But I wonder how this affects future upgrades of already-installed sites and how the data already existing in current databases gets preserved.

- Writing the .install file is really the killer here. I see the Profiler module, but it is still in DEV for 7 and has so little information about how exactly it is used. I feel like I am swinging a bat in the dark while wearing a blindfold after drinking a 1/5 of moonshine.

- In the install profiles...Do we need to move all modules into the profile folder or can they all be fed remotely? They few d7 distributions seem to be 1/2 and 1/2 on this, and most of them are simpler than what I am doing. Does the .info file dependencies declarations simply indicate that - just dependencies? I suppose this is completely different than a Drush make file

So many questions and loose ends.

@kannary100:

- No, you do not need to include a drush make file if you're creating an installation profile for in-house use. It may be handy to have a drush make file in your install profile, but that all depends on your use case.
- Features is a tough nut to crack, and it really is an art to get your features right. I'm not sure I would bother to "featurize" an existing site, though. You've already done all the work, why bother? Features is great for building new sites, since all you need to do is turn on a "blog feature", for instance, and you have a fully functional blog.
- Yeah, there's no way to get around having to understand the drupal api and actually do some coding. My best advice: keep looking at examples.
- The modules themselves can either be in the profiles directory or somewhere in the sites directory. The install profile doesn't really care. If you're using aegir, though, and you have a multi-site setup, then you'll need to think carefully about this question. Which modules are generally shared by all sites on your multi-site platform, and which are profile specific? Do you have multiple sites that use the same installation profile, or is each install profile used for a single site?

with D7 it seems that only the "profile" directory is searched.
But if your custom module *is* also your profile, nothing stops you from using a symlink from
"profiles" to "sites/all/modules", just tested this and it seems to work fine.

please note that if you want to inherit from the "standard" profile but don't want to activate RDF you may
have to define a void rdf_mapping_save() in your hook_install() to avoid failures during installation.

but the main issue is that module dependencies[] and profile dependencies[] don't have the same meaning.
However, hook_profile_modules can be used as an alternative... which is apparently not fired anymore...

The D7 standard installation profile basically puts everything into the .install file. Any tips on when and how to break up a complex installation profile into multiple files?

For drupal 7 there is hardly any clarification how one could make a theme available for download as a .zip archive with some pre-configured site content. These installation profile methods either seem A)overly complicated or B) tailored toward drush. That is fine, but non-programmers/non-command-line enthusiasts may want to build a simple install profile with a few pieces of content set up to display some features of a theme.

How can we find out more about this type of installation profile for D7?

I am also a non programmer who has heard that Drupal is friendly to designers. I want an install profile to be able to set up development, staging and production sites - to be able to test new work and keep my work/modules/themes in sync. The part that intimidated me about Drush was learning the bash scripts as indicated in the Drush Read me file and the bash script tutorials I started to review. I don't mind doing some basic coding, and chmod, but I don't want to memorize a whole new language. Drupal is hard enough for me to get a handle on, but I want my sites to be stable.

note from 07/20/11 Just bought The Mac OS X Command Line: Unix Under the Hood. If I can dummy down how to do the install profile, drush will post back here later. Maybe the book will help me to find a link I understand and I will post that too when it comes together.

note from 07/24/11 There are some good tutorials in youtube for BASH Scripts for Mac that are easy to follow here: http://www.youtube.com/watch?v=QGvvJO5UIs4

MaggieL

I'm not afraid of writing code at all, my issue is time savings. If I have to painstakingly document all my modules, themes and other resources to create an installation profile then it's not that big of a time saver to me. It would be a lot nicer if either core or drush had a way to simply create an installation profile of the currently running installation.

One thing to watch out for is to make sure that you put hook_install_tasks in your .profile file. I had it in the .install file and it cause the profile to half work.

PJW

which execute sequence of a installation profile ?
.install go first and then .profile or vice versa.

(I don't have a .install file, but I'm guessing it's next.)

But what I don't know is how to control the load order of modules in the .info

This documentation is EXCELLENT. Really helpful and thank you to everyone who has been involved!

Thanks for the really helpful & clear documentation! Is there any chance you could supply the code for the example you mentioned:

"For example, if you are building an install profile specifically for sites using a certain language, you might want to remove the localization steps and simply configure the language settings yourself."

I tried doing this various ways and didn't have much success.

Just use

<?php
theme_enable
($theme_list);
?>