A basic install profile
This is the second post in my series on install profiles. It covers the anatomy of an install profile and creating .install and .profile files. We create a simple brochure style install profile which is based on the standard D7 profile with a few customizations of my our own.
If you haven't already, take a look at my last post on install profiles and create the folder structure described there. Don't worry about the files as we'll create them in this post.
The folder structure
For reference, the structure will be as follows (I've added "libraries" since the last post):
profiles/brochure
profiles/brochure/libraries
profiles/brochure/modules
profiles/brochure/modules/contrib
profiles/brochure/modules/custom
profiles/brochure/modules/features
profiles/brochure/themes
I've found splitting the modules up into the folders as shown here to work best while developing drupal sites. The contrib folder will store any contrib modules we use, the custom folder will be all custom modules we write (I also use this for contrib modules that I'm a maintainer of), and features will store any Drupal features that we create.
brochure.info
Just as with any theme or module we'll need to start with a .info file. Basing this off of the minimal.info we might have something such as:
name = Brochure
description = Install a basic brochure style of website
core = 7.x
; Core modules
dependencies[] = block
dependencies[] = dblog
dependencies[] = field_ui
dependencies[] = file
dependencies[] = help
dependencies[] = image
dependencies[] = menu
dependencies[] = number
dependencies[] = options
dependencies[] = path
dependencies[] = taxonomy
dependencies[] = toolbar
dependencies[] = rdf
; Sub core modules
dependencies[] = boxes
dependencies[] = context
dependencies[] = ctools
dependencies[] = features
dependencies[] = libraries
dependencies[] = pathauto
dependencies[] = strongarm
dependencies[] = token
dependencies[] = views
; Development tools
dependencies[] = devel
files[] = brochure.profile
I personally prefer to split up my modules by an arbitrary category. In this case "sub core" modules are all of the modules that I tend to use on almost all of my sites, like views and ctools. I also generally will use certain modules during development that would be disabled when the site is ready to go live, like devel or even dblog.
I'm not sure the files[] = brochure.profile
strictly needs to be defined here as that's normally used for defining files that contain classes, but since both minimal and standard do it, it's probably a good idea.
Download all of the contrib modules specified in the .info file above and drop them into profiles/brochure/modules/contrib/.
brochure.install
Again, the easiest thing to do here will be to base your custom
profile off of minimal.install (or standard.install). In fact, we want everything that the minimal.profile has so you can just copy that straight out and change "function minimal_install()" to "function brochure_install()".
The first part of the file defines the blocks to use on the site. For the moment there's no reason we can't just go with the default blocks.
function brochure_install() {
// Enable some standard blocks.
$default_theme = variable_get('theme_default', 'bartik');
$values = array(
array(
'module' => 'system',
'delta' => 'main',
'theme' => $default_theme,
'status' => 1,
....
The default theme being used is bartik, which again, is fine for the moment. As we're just going to be installing the site by hand (i.e. not using Aegir), we can just change that theme after install since each brochure site will likely have it's own custom theme.
Looking through the minimal install profile we can see that it defines the following blocks for display:
Module
Block (delta)
Region
system
main
content
user
login
sidebar_first
system
navigation
sidebar_first
system
management
sidebar_first
system
help
help
If you want to remove or add blocks just copy the way they've done it here. Of course, if you're using contexts and features this becomes unnecessary.
The next thing done in the .install is setting the variables and permissions, and that's about it.
The standard.install takes this stuff to the next level. It does the following:
- Defines filter formats
- Sets the default theme
- Sets up the blocks
- Creates two node types (page and article)
- Sets up RDF mappings
- Configures node options, comments, and user profile stuff
- Creates a taxonomy vocabulary called "tags"
- Creates and adds a taxonomy reference field to the article type
- Creates and adds an image field to the article type
- Sets up user role permissions
- Adds a main menu to the site
- Enables and sets a default administrative theme
Looking through the standard.profile the first time was a bit of overwhelming, particularly with the image field aspect of it (more so because at the time I had no experience with entities or fields). If you take some time going over the rest of the code you'll notice it's all actually quite straight forward module development stuff.
Building a complex install profile requires a very strong knowledge of the Drupal API or at least willingness to learn and spend hours in frustration banging your head on the table when things don't work (I have the bruises to show for it). However, if you're not a strong programmer but relatively comfortable working with features, in one of my next posts I'll try and demonstrate how to completely replace the standard.install using features, so you may find that much more enjoyable :).
Now as it turns out, the standard install profile already gives us the basics for a simple brochure style website! Who'd a thunk!? All we need to do is remove a couple things provided in there and add a few tricks of our own.
At this point, all I want is a few pages of text (i.e. a brochure) for the website. No blog necessary. So copy everything into brochure.install with the exception of the article node type and any fields added to it, the taxonomy field, the article specific rdf mapping, and the comment settings. Also remove the comment related permissions since comment isn't being installed in this profile either. If you don't remove the comment related permissions, your install profile will fail.
brochure.profile
For now we can simply copy minimal.profile (which is identical to standard.profile) and rename the function to start with brochure_ instead of profile_. All this is doing is setting the default site name on install form.
Additions to the install profile
There are still a number of customizations I'll want on a basic brochure site including:
- More customized initial install form.
- A WYSIWYG editor
- A customized set of shortcuts for the client
- Adding a client user account
- Roles for the client to use (content editor, for example)
When building an install profile in practice I will always start with a base site and then configure it as I want it to be. I add every single little configuration step back into the install profile as I go. For many of the configurations I want to do I need to browse through the core code to understand how components are added and updated. That's how I solved #3 below, for example.
1. When installing a new site you're presented with a form that you must fill in the site mail, account name and mail, country, and timezone. 95% of all of the sites I would build with a profile like this would have the exact same options on the initial install page, so why should I manually fill them in each time. The standard and minimal profiles automatically set the site name, but I'll take this one step further. In my brochure.profile I've added the following:
function brochure_form_install_configure_form_alter(&$form, $form_state) {
// Pre-populate the site name and email address.
$form['site_information']['site_name']['#default_value'] = $_SERVER['SERVER_NAME'];
$form['site_information']['site_mail']['#default_value'] = 'admin@hatchwebstudio.com';
// Account information defaults
$form['admin_account']['account']['name']['#default_value'] = 'admin';
$form['admin_account']['account']['mail']['#default_value'] = 'admin@hatchwebtudio.com';
// Date/time settings
$form['server_settings']['site_default_country']['#default_value'] = 'CA';
$form['server_settings']['date_default_timezone']['#default_value'] = 'America/Vancouver';
// Unset the timezone detect stuff
unset($form['server_settings']['date_default_timezone']['#attributes']['class']);
// Only check for updates, no need for email notifications
$form['update_notifications']['update_status_module']['#default_value'] = array(1);
}
The last item there changes the update settings so that I won't receive an email for security updates but a message will still be displayed on the site.
2. Adding a wysiwyg to the site is fairly simple. Install something like ckeditor to profiles/brochure/modules/contrib and download the ckeditor library to profiles/brochure/libraries. (Yes, we could use the wysiwyg module for this too, and in fact in practice that's probably what you should choose. However, wysiwyg profiles can be tedious to setup in install profiles and work to make them exportable in features is still underway http://drupal.org/node/624018).
dependencies[] = ckeditor
If you install the ckeditor 3rd party code into your libraries folder you'll also need to add the following line to your .install:
variable_set('ckeditor_path', 'profiles/brochure/libraries/ckeditor');
The reason you need to hardcode the ckeditor path is because ckeditor does not properly support librares (see this issue for more details). This means that it doesn't know to find libraries in profiles (and thus will never find your ckeditor 3rd party code). You could simply install the 3rd party code into the ckeditor module folder itself, but the "clean" way is to use libraries.
These kinds of problems are by no means unique to ckeditor and you'll more than likely run into them as you customize your profiles. Many modules will work perfectly fine until you want to use them in an install profile. The best way of getting around it is to find and fix the issue and submit a patch.
3. For my shortcuts I'll simply use the core shortcut module with an additions. I want to add a quicker way to add a new page from the shortcuts bar. I've added the following code to do just that into my .install.
module_load_include('inc', 'shortcut', 'shortcut.admin');
$shortcut_set = shortcut_set_load('shortcut-set-1');
$shortcut_link = array(
'link_title' => 'Add page',
'link_path' => 'node/add/page',
'menu_name' => $shortcut_set->set_name,
);
shortcut_admin_add_link($shortcut_link, $shortcut_set, shortcut_max_slots());
shortcut_set_save($shortcut_set);
Ensure this code goes after the page content type is created and after menu_rebuild() to ensure that the 'node/add/page' path exists.
4. For every brochure site I create I will need a client account, so I'd like to automate the creation of that as well. Unfortunately the client name and email address won't be identical between each site, so we'll need some user input for that. This will be a focus of the next post.
5. Though not strictly necessary for such a simple site, it makes sense to put our client into some sort of a role besides "authenticated user". This can be done in an identical manner to the way the 'administrator' role was created in standard.install.
$client_role = new stdClass();
$client_role->name = 'content editor';
$client_role->weight = 3;
user_role_save($client_role);
user_role_grant_permissions($client_role->rid, array('administer nodes', 'create url aliases', 'customize shortcut links', 'administer site configuration', 'access site in maintenance mode', 'view the administration theme', 'access site reports', 'block IP addresses', 'administer taxonomy', 'access toolbar', 'administer users'));
My goal here isn't to lock out the client account, but instead remove obvious access to parts of the site that they won't need to use.
Conclusion
When it comes down to it creating an install profile can be as simple or complicated as you want to get. The more complicated the more tedious it will become, but also the more you'll be able to do (and learn). Install profile skills translate right back into module development anyway.
Initially it may seem that unless you plan on creating dozens of sites under the same profile the ROI on building an install profile will not be high. However, as I'll get into later you can use the install profiles as a best practice to help with automating updates to your production site such that it will make sense even if you only ever have a single installation on your profile.
In the next post I'll write more about adding additional site customizations, additional steps, and forms directly into your install profile so that you will get a much more streamlined site out of the box.