Creating an installation profile

When I start developing a new website from scratch, I don't spend hours creating a new Drupal site, install the module and themes I need, and then troll through all the configurations to have the setup I want. No, I usually start from a previous, basic Drupal site build that has all the modules, themes and configurations I need as a foundation to build on - therefore I can replicate that in some way so I don't need to keep building it when I want to start work on a new site. In the past, what I would do is cut and paste files from a base Drupal build to my new site location and then do a database export import. It was then just a case of changing the settings.php file with the new site information. In Drupal 8, I want to do the same thing but create the basic site build using composer and a custom installation profile. I will also create a Bootstrap sub theme, host it on GitHub, and have the install download and include that as a dependency. This should save me a little bit of time otherwise I just keep repeating the process of setting up a Bootstrap base theme using a SASS compiler.

I have a Drupal 8 site all set up, with all the contrib modules/themes installed and configured how I like it. It also includes a custom Boostrap sub theme. We are going to make an installation profile of that site. First thing is to think of the profile machine name, one with using only lowercase letters and underscores if needed. For this example I'm going to call it thecarneyeffect.

Creating the folder and files

  • Create a folder called thecarneyeffect
  • Inside that folder, create the files:
    • thecarneyeffect.info.yml
    • thecarneyeffect.install
    • thecarneyeffect.profile (optional and not used in this example)
  • Create the folders config/install (so you end up with /thecarneyeffect/config/install)

thecarneyeffect.info.yml

Go to the command line of the site Drupal site you are making an installation profile of, and do the following command:

drush cex

This will export the configuration as files in the sync directory. Read here to find where that directory is. I always change this location to a folder above the Drupal web root directory. In the sync directory there is a file called core.extension.yml. If I open that up it will show all the modules and themes I want to add to my thecarneyeffect.info.yml file. So I copy it over making sure I'm changing it so it's using the correct format as seen below:

name: The Carney Effect
type: profile
description: 'Custom installation profile for The Carney Effect'
version: VERSION
core: 8.x
dependencies:
  - block
  - breakpoint
  - ckeditor
  - config
  - contextual
  - ctools
  - dblog
  - devel
  - dynamic_page_cache
  - editor
  - field
  - field_ui
  - file
  - filter
  - image
  - imce
  - kint
  - libraries
  - link
  - menu_link_content
  - menu_ui
  - node
  - page_cache
  - path
  - quickedit
  - rdf
  - responsive_image
  - syslog
  - system
  - taxonomy
  - text
  - token
  - toolbar
  - update
  - user
  - views
  - views_ui
  - pathauto
themes:
  - stark
  - stable
  - classy
  - bartik
  - bootstrap
  - bootstrap_sub

Not the last line is the name of my bootstrap sub theme.

thecarneyeffect.install

I basically copied the parts I wanted to use from the minimal and standard profiles in core.

<?php

/**
 * @file
 */

use Drupal\user\Entity\User;
use Drupal\user\RoleInterface;
use Drupal\shortcut\Entity\Shortcut;

/**
 * Implements hook_install().
 *
 * Perform actions to set up the site for this profile.
 *
 * @see system_install()
 */
function thecarneyeffect_install() {
  // Set front page to "node".
  \Drupal::configFactory()->getEditable('system.site')->set('page.front', '/node')->save(TRUE);

  // Allow visitor account creation, but with administrative approval.
  \Drupal::configFactory()->getEditable('user.settings')->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save(TRUE);

  // Assign user 1 the "administrator" role.
  $user = User::load(1);
  $user->roles[] = 'administrator';
  $user->save();

  // We install some menu links, so we have to rebuild the router, to ensure the
  // menu links are valid.
  \Drupal::service('router.builder')->rebuildIfNeeded();

  // Enable the admin theme.
  \Drupal::configFactory()->getEditable('node.settings')->set('use_admin_theme', TRUE)->save(TRUE);
}

config/install folder

Copy all the settings files from the sync folder in your Drupal 8 site to the config/install folder in your profile. You MUST follow the next steps carefully or there will be errors during installation.

  • In the config/install folder that contains the settings files you just copied over, delete the following files:
    • core.extension.yml
    • file.settings.yml
    • update.settings.yml
  • Remove all the UUIDs that appear on the first line of all the settings files. You can search replace but in my case there are hundreds of files, so the best way is to do it from the command line. Go to your profiles folder and run the following, replacing the path with the path of your profile folder:
find ./ -type f -exec sed -i '/^uuid: /d' {} \;

Your profile should now be ready.

composer.json

I need to make sure I run 'composer require' for all the modules and themes I'm using so that they are included as dependencies in the composer.json file. If you don't know already, you can see here how to include to use composer to manage Drupal site dependencies. You should now have a composer.json file that look like this:

{
    "name": "drupal-composer/drupal-project",
    "description": "Project template for Drupal 8 projects with composer",
    "type": "project",
    "license": "GPL-2.0+",
    "authors": [
        {
            "name": "",
            "role": ""
        }
    ],
	"repositories": {
		"drupal": {
			"type": "composer",
			"url": "https://packages.drupal.org/8"
		},
		"bootstrap_sub": {
			"type": "package",
			"package": {
				"name": "drupal/bootstrap_sub",
				"version": "dev-master",
				"type": "drupal-theme-custom",
				"source": {
					"url": "https://github.com/web-assistant/bootstrap_sub",
					"type": "git",
					"reference": "master"
				}
			}
		}
	},
    "require": {
        "composer/installers": "^1.2",
        "drupal-composer/drupal-scaffold": "^2.2",
        "cweagans/composer-patches": "~1.0",
        "drupal/core": "~8.0",
        "drush/drush": "~8.0",
        "drupal/console": "~1.0",
        "drupal/ctools": "^3.0@alpha",
        "drupal/imce": "^1.4",
        "drupal/libraries": "3.x-dev",
        "drupal/token": "^1.0@RC",
        "drupal/pathauto": "^1.0@beta",
        "drupal/bootstrap": "^3.1",
        "drupal/bootstrap_sub": "dev-master"
    },
    "require-dev": {
        "behat/mink": "~1.7",
        "behat/mink-goutte-driver": "~1.2",
        "jcalderonzumba/gastonjs": "~1.0.2",
        "jcalderonzumba/mink-phantomjs-driver": "~0.3.1",
        "mikey179/vfsStream": "~1.2",
        "phpunit/phpunit": "~4.8",
        "symfony/css-selector": "~2.8",
        "drupal/kint": "^1.0@RC",
        "drupal/devel": "^1.0@RC"
    },
    "conflict": {
        "drupal/drupal": "*"
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "autoload": {
        "classmap": [
            "scripts/composer/ScriptHandler.php"
        ]
    },
    "scripts": {
        "drupal-scaffold": "DrupalComposer\\DrupalScaffold\\Plugin::scaffold",
        "pre-install-cmd": [
            "DrupalProject\\composer\\ScriptHandler::checkComposerVersion"
        ],
        "pre-update-cmd": [
            "DrupalProject\\composer\\ScriptHandler::checkComposerVersion"
        ],
        "post-install-cmd": [
            "DrupalProject\\composer\\ScriptHandler::createRequiredFiles"
        ],
        "post-update-cmd": [
            "DrupalProject\\composer\\ScriptHandler::createRequiredFiles"
        ]
    },
    "extra": {
        "installer-paths": {
            "web/core": ["type:drupal-core"],
            "web/libraries/{$name}": ["type:drupal-library"],
            "web/modules/contrib/{$name}": ["type:drupal-module"],
            "web/profiles/contrib/{$name}": ["type:drupal-profile"],
            "web/themes/contrib/{$name}": ["type:drupal-theme"],
            "web/themes/custom/{$name}": ["type:drupal-theme-custom"],
            "drush/contrib/{$name}": ["type:drupal-drush"]
        }
    }
}

Including custom modules/themes

Remember I included my custom sub theme at the bottom of thecarneyeffect.info.yml called bootstrap_sub. I want to add this as a dependency in the composer.json file so it gets downloaded along with all the other config modules/themes. To do this, I added my custom sub theme on GitHub so I can use that as the repository. I've done that and you can find it here. The next bit is to alter the composer.json file so it both knows the location of that theme, and includes it as a dependency.

@todo complete this