Drupal 8 profile creation
CMS

Saving development time with a Drupal Installation Profile

For every new Drupal project there are many components and setup steps that are the same or similar to other projects.  These steps are repetitive and time consuming.  We needed to be able to standardize and automate the setup process to reduce human error and increase efficiency.

An Install profile is used to package up modules and themes to be setup as a part of the installation when someone chooses to install a Drupal site with a certain install profile.

The primary usage of them is setting up the website and make it ready for usage right after the installation.

Here is an example of some of the steps that are repeated for every project (doing it the traditional way):

  • Download & Enabling modules
  • Download & Enabling themes
  • Creating content types
  • Gathering data from the user on the configuration page
  • Setting up necessary configurations
  • Per-bundle node listing pages, blocks, feeds

 

Drupal has predefined profiles named ‘standard’, ‘minimal’. In our scenario we have extended the standard profile with our custom installation tasks.

We are going to create our own  Drupal 8 installation profile which will be called “corporate” and we will see, how these installation steps are handled.

Creating the Structure.

The structure has following files.

  1. corporate.info.yml
  2. corporate.profile
  3. corporate.install
  4. Config folder.

All the above files should be inside the ‘/profiles/your_profile’ folder under your ‘Drupal root Folder’. Here our profile name is “corporate”, So we have to do the action under the following directory.

Drupal_root_folder/profiles/corporate

corporate.info.yml  is a configuration file, which is the similar to module info file which is a base thing for our installation profile to be recognized by Drupal.

corporate.profile has access to almost everything a normal Drupal module name.module file does because Drupal is fully bootstrapped before almost anything in the profile runs.

corporate.install provides Install, update and uninstall functions for the profile.

Config folder can contain configuration files. You can start by taking the configuration directory (config folder) of an installed, configured site and copying it into a config folder in your profile. Or you may just take several configuration files you need and customize them according to your needs.

In our case, we have built the below components in the process of the profile installation

  1. Enable the custom theme (our own base theme)
  1. Provided the multiple languages selection for the users during installation.
  2. Provided the configuration page for setting Mailchimp API Key
  3. Enable the custom blocks and assign them to regions.

 

1.Enable the custom theme.

The themes that should be installed as part of the installation process must be listed out in profilename.info.yml file.

themes:
 - bartik
 - seven
 - bootstrap
 - bootstrapmade

Drupal8 installation profile contains many configuration files. We’ve taken a system.theme.yml config file and put it in the config/install folder of our profile.

Existing code :

admin: seven
default: bartik

Changed Code :

admin: seven
default: bootstrapmade

Note: Before installation the profile please make sure the bootstrapmade custom theme should be placed in theme folder

  • All install, update and uninstall functions are provided in profilename.install file.
  • In order to install the theme and set it as default, perform the following actions under hook_install() function.
hook_install() {
 \Drupal::service('theme_installer')->install(['bootstrapade']);
 \Drupal::service('theme_handler')->setDefault('bootstrapmade');
}
2. Provided the multiple languages selection for the users during installation.

hook_install_tasks() allows us to create new steps in the installation process and it returns an array of tasks/steps to be performed by an installation profile. Each task you define in hook_install_tasks will have a callback function which you must separately define and which is called when your task is run.

In our case the hook is ‘corporate_install_tasks‘ and the callback function is ‘corporate_multilingual_configuration_form

The display_name is used as the text displayed in the sidebar with the install profile steps as can be seen in the screenshot below.

<?php

use Drupal\Core\Form\FormStateInterface;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\corporate\Form\ConfigureMultilingualForm;

/**
* Implements hook_install_tasks().
*/
function corporate_install_tasks(&$install_state) {
  // Determine whether the enable multiligual option is selected during the
  // Multilingual configuration task.
  $needs_configure_multilingual = (isset($install_state['corporate']['enable_multilingual']) && $install_state['corporate']['enable_multilingual'] == TRUE);
  $myprofile_needs_batch_processing = \Drupal::state()->get('myprofile.needs_batch_processing', FALSE);
  return array(
    'corporate_multilingual_configuration_form' => array(
      'display_name' => t('Multilingual configuration'),
      'display' => TRUE,
      'type' => 'form',
      'function' => ConfigureMultilingualForm::class,
      ),
    'corporate_configure_multilingual' => array(
      'display_name' => t('Configure multilingual'),
      'display' => $needs_configure_multilingual,
      'type' => 'batch',
      ),
    );
}

/**
* Batch job to configure multilingual components.
*
* @param array $install_state
*   The current install state.
*
* @return array
*   The batch job definition.
*/
function corporate_configure_multilingual(array &$install_state) {
  $batch = array();

  //If the multiligual config checkbox were checked.
  if (isset($install_state['corporate']['enable_multilingual'])
    && $install_state['corporate']['enable_multilingual'] == TRUE) {

    //Install the Varbase internationalization feature module.
    $batch['operations'][] = ['corporate_assemble_extra_component_then_install', (array) 'corporate_internationalization'];

    //Add all selected languages and then translatvarbase_hide_messagesion
    // will fetched for theme.
    foreach ($install_state['corporate']['multilingual_languages'] as $language_code) {
      $batch['operations'][] = ['corporate_configure_language_and_fetch_traslation', (array) $language_code];
    }
    return $batch;
  }

}
/**
* Batch function to add selected langauges then fetch all traslation.
*
* @param string|array $language_code
*   Language code to install and fetch all traslation.
*/
function corporate_configure_language_and_fetch_traslation($language_code) {
  ConfigurableLanguage::createFromLangcode($language_code)->save();
}
3. Provided the configuration page for setting Mailchimp API Key

As I said hook_install_tasks() returns keyed array of tasks the profile will perform during the final stage of the installation. we have a keyed value ‘function’ which is being used to force the installer to call a different function when the task is run (rather than the function whose name is given by the array key). This could be used, for example, to allow the same function to be called by two different tasks.

In our case, we have reused the ‘MailchimpAdminSettingsForm’ Class So MailChimp settings page will be included in installation step.

<?php

use Drupal\Core\Form\FormStateInterface;
use Drupal\mailchimp\Form\MailchimpAdminSettingsForm;
/**
 * Implements hook_install_tasks().
 */
function corporate_install_tasks(&$install_state) {
  return array(
   'corporate_mailchimp_configuration_form' => array(
      'display_name' => t('Mail Chimp configuration'),
      'display' => TRUE,
      'type' => 'form',
      'function' => MailchimpAdminSettingsForm::class,
    ),
  );
}

Here we have used class ‘MailchimpAdminSettingsForm‘ as a function for the task.

4. Enabling custom blocks for profile installation.

Configuration management shouldn’t export custom blocks as it results in broken blocks. A custom block is made of two entities, one for the placement and one for the actual content. Only the actual placement can be exported with configuration management initiative. The content can not.

Therefore this will result in “Block description Broken/Missing” error on site where the config is imported. And since there is no option to disable custom blocks from being exported through Configuration management this will break the functionality.

Thereby, we create blocks in the custom module and enable the module through profile dependencies.

In Drupal8, all the custom modules are placed in <root folder>/modules/custom.

1. Create the info.yml file and place it in <root folder>/modules/custom/your_module.

Example : hello_world.info.yml

name: Hello World Module
description: Creates a page showing "Hello World".
package: Custom
type: module
core: 8.x

2.Create a file inside modules/custom/your_module/src/Plugin/Block/YourBlockName.php

The Drupal block manager scans your modules for any classes that contain a @Block Annotation.
The snippet below makes use of the @Block annotation along with the properties “id” and “admin_label” to define a custom block.

Example : HelloBlock.php

<?php
    /**
     * @file
     * Contains \Drupal\hello_world\Plugin\Block\HelloBlock.
     */
    namespace Drupal\hello_world\Plugin\Block;

    use Drupal\Core\Block\BlockBase;

    /**
     *
     * @Block(
     *   id = "hello_block",
     *   admin_label = @Translation("Hello Block"),
     *   category = @Translation("Custom")
     * )
     */
    class HelloBlock extends BlockBase {
      
    /**
      * {@inheritdoc}
      */
      public function build() {
       return [
       '#type' => 'markup',
       '#markup' => '<p> Hello, Welcome!</p>'
       ];
     }
   }

3. clear your cache.

4. enable the custom module:  In order to enable the module during profile installation, list out the module in your profile_name.info.yml dependencies.

5. placing the block in a region:  

export the yml file of the respective block  in <root_folder>/profiles/your_profile/config/install>For exporting configuration files
1. Go to block layout of admin interface and place the block in a particular region.
2. Go to configuration/development/configuration synchronization/export/single item and copy the respective block
configuration file and save it with the suggested yml file name.

Conclusion:

With the above set of details you have seen how you are able to club together a set of steps which you would generally repeat for a typical Drupal installation for a new development. Different profile can be created based on similar features/functionality  like corporate portal, blog site, eCommerce site etc. Creating a profile ensures you have these steps already in place configured so that you can start focusing on the project specific requirements.

 

About The Author

Rajesh Kairamkonda

Drupal Developer

Leave a Reply

*