Why you should not always use Drupal Features for settings, and what you can use instead

The Drupal Features module covers a lot of our needs with automating the deployment of database settings for Drupal 7. It allows you to export configuration to code and nicely wrap it up as a module. This means you easily deploy your changes to the live site (or a staging site) without having to repeat the configuration changes. It also means you can apply the changes to a different site.

If you are new to Features, check out my Drupal 7 Features tutorial.

But using Features is not always the best approach. Even if you can export something using Features, it doesn't mean you should.

An example

Consider the following: You have a setting in an admin form that you want to deploy to the live site. For example, the site name and slogan, which you can set in Administration > Configuration > System.

Drupal site name and slogan fields

You can add that to a feature by using the Strongarm module. Strongarm allows you to add any Drupal variable to a feature. System settings like site name and slogan are stored as Drupal variables (if you would like to learn how to create your own admin form which stores variables like this, check out my post Create your first Drupal admin interface)

But what happens when the administrator wants to change the site name or slogan setting on the live site? The feature becomes overridden because the setting stored in the database on the live site no longer matches the setting stored in code in the feature.

At some point in the future, you do another deployment to the live site. You have updated the same feature again and you decide you need to revert the feature for its changes to take effect (it is generally good practice to do a features revert all on every deployment). At this stage, you are blissfully unaware that the administrator has changed a setting that happens to be stored in the feature you just re-deployed.

The site name and slogan setting change that the administrator made is gone. Nuked. Destroyed. Why? Because you just reverted the feature, which reverts any database settings that the feature controls and turns it back to the setting that is stored in code. You probably won't even realise that you have destroyed the administrators setting change because you fully intended to revert the feature.

You are going to end up with one unhappy administrator. Best case scenario? The administrator informs you so you can fix it. Worse case scenario? He/she doesn't notice and you have a bug. The middle case scenario is that he/she changes it back but doesn't tell you. You then do another deployment in the future and it gets reverted again. The administrator thinks it is a weird glitch in the matrix and changes it again. This song and dance can carry on for quite a while before the administrator mentions it to you. I have seen this happen a lot.

The Solution

Right, so we know the problem. How do we solve it?

Simple: Don't export settings in a feature if you fully intend for it to be changed on live.

Now I am sure you are thinking that it means going back to the old school way of manually updating the live site with the setting when you first do the deployment. Not the case. The goal is to still do as much in code as possible without having to manually make manual configuration changes to the live site.

To set an admin setting during deployment, you just need to use the variable_set() function in a deployment module.

Create a site deployment module

Create your module with these three files:

  1. site_deployment.info
  2. site_deployment.module
  3. site_deployment.install

The info file

The info file should contain the following:

  1. name = Site Deployment
  2. description = Deployment module, used to automated changes to this site
  3. core = 7.x
  4. version = "7.x-1.x-dev"

The module file

The module file doesn’t need to contain any working code. We will simply include a comment.

  1. <?php
  2. /**
  3.  * @file
  4.  * Module file for Site Deployment
  5.  */

The install file

In the install function, you can write an implementation of hook_update_N for each deployment. This is the heart of the site deployment module.

Let’s take a look at the code for the first function.

  1. <?php
  2. /**
  3.  * @file
  4.  * Install file for Deploy Update
  5.  */
  6.  
  7. /**
  8.  * Deployment function for 1st deployment
  9.  */
  10. function site_deployment_update_7000() {
  11. variable_set(variable name, variable value);
  12. }

This sets the variable for the setting that the administrator is likely to change on the live site. For this to take effect, you just need to deploy site_deployment to the live site and run update.php

In our example, we want to set the site name and site slogan. This will achieve our goal of automatically deploying changes with code and still allow it to be edited on the live site.

To do that, we just need to add two variable sets to an update function in the site deployment module. The first one sets the site name and the second the site slogan.

  1. /**
  2.  * Set the site name and slogan.
  3.  */
  4. function site_deployment_update_7000() {
  5. variable_set('site_name', 'Wonderful website');
  6. variable_set('site_slogan', 'A wonderful website about Drupal');
  7. }

Finding the variable name

The variable name for the site name is site_name and for the site slogan is site_slogan. You might be wondering, how do you find the variable name and value for another variable?

There are a couple of ways

  1. When you look at the admin form, view source (or inspect the element). The html name attribute is the name of the variable
    Variable name as html attribute
  2. Look in the variable table in the database. This will show you all of the variables that are saved to the database.
    Variable tabe in database
  3. Use the variable editor that comes with the Devel module.
  4. Use the Drush vget command. Get a list of all current variables and their values with drush vget. Or find variables from specific modules by using piping the output to grep. E.g. find variables from pathauto: drush vget | grep pathauto. [Thanks David for suggesting this in the comments.]

Once you get used to writing update hooks with variable_set() it becomes second nature. Even when I am updating a setting on my local environment, I normally write the variable_set(). This is the full process:

  1. Test out the setting change the traditional way, by clicking it on the form
  2. Once you are happy with what you have, change it back.
  3. Create a new update hook in your deployment modules install file.
  4. Run update.php (or drush up) on your local environment. Check the setting and make sure it has changed
  5. Deploy your deployment module to your development server, or whichever server is next in line (it could be straight to QA or Staging). Run update.php there. Now the client, reviewer etc can view the change and sign it off (or not). You now safely know that you don't have to remember to manually make this change on the live site at some future date when it is supposed to go live. You just deploy the deployment module and run update.php and you're done.

Wrapping up

Using code to store and deploy database settings is a wonderful thing but the Features module is not the right hammer for every nail. Setting variables in a deployment module is one of the quickest ways to get started with using a deployment module and it solves the problem of a feature becoming overridden when settings are changed on a live site.

Learn Drupal Features

Make your life easier by packaging up Drupal site building settings in Features modules. No coding required! 

Free 5 day course where you will learn to create and update your own Drupal Feature module.

Get Day 1 now


Conquer Drupal 8 Module Development

Don't struggle to conquer Drupal 8 module development. Action packed lessons where you will work along building your own real world modules.

20% launch discount available now!

Find out more


Comments

Nice post.

The variable dump module was very helpful for this sort of process in D6 https://www.drupal.org/project/variable_dump

Especially for more complex variables, or modules with many variables.

I have used in in D7, but it did require a little hacking.

Blair Wadman's picture

Thanks Sean!

Yeah variable dump was handy. Do you have your D7 version in a repo somewhere?

Profiler Builder and Drush Recipes sound like they will help with this in the near future.

The problem with this approach is that you have to type everything manually. Another way that is much faster in the long run is to write your own module that accepts the same formats but doesn't get tracked. That way you can still export configuration through Features which saves a lot of manual work and potential bugs. Of course you still need to write that module but what I did was basically to copy the relevant functions from Features so the amount of code I had to write manually was quite small in comparison.

Blair Wadman's picture

Sounds like a good approach. Do you have a tutorial or walk through of some sort on this?

You can actually still use features. But instead of exporting via strongarm you export via defaultconfig module (https://www.drupal.org/project/defaultconfig). This puts the setting in code but lets you change it in the admin UI without showing a feature as overridden. So there's no need for a custom module, defaultconfig works hand-in-hand with Features.

Blair Wadman's picture

Thanks for this. According to the project page, defaultconfig exports "permissions and roles to provide default settings for installations profiles"

Can it be used for sites that don't use install profiles and does it handle more than permissions and roles?

Yep. Default config covers most everything strong arm does.

Hi Blair,

The link to Strongarm should be drupal.org/project/strongarm

N

Blair Wadman's picture

Good spot Nick, thanks!

Another useful way to lookup variable names is with the `drush vget` command (short for variable-get). Executing the command with no arguments returns a list of all current variable names and values. Pipe the output to grep and you have an easy way to find variables provided by specific modules or to fuzzy-search for variable names that you just can't quite remember: e.g. `drush vget | grep pathauto`

Blair Wadman's picture

Thanks David! I've added this to the post. :)

Or just use a second argument for the drush vget command to search for variables:

drush vget pathauto

Who's changing configuration, such as site title and slogan on a production site?

Bad administrator.

Apart from that, some useful info about deployment modules. Thank you!

As well as site_deployment_update_7000() wont you need to duplicate the variable_set() in to a site_deployment_install() hook function for the initial site creation ?

Blair Wadman's picture

Good point. If you want to set a variable for the initial site creation, or if the site deployment module is installed and enabled on an existing site for the first time, then yes it would need to be done in site_deployment_install().

I'll update the article accordingly. Thanks!

Add new comment