Let's start with the most important "best practice" of applying Drupal updates: stay out of your production ("live") site. Use a local environment (such as Acquia's Dev Desktop, WAMP, MAMP, etc.), remote development instance, or just about anything that's not your live server. The point is that upgrading modules and Drupal core can often cause unintended consequences, and you don't want to be on your live site if/when that happens.

Getting started

  1. We're going to use drush (a Drupal command line tool), so make sure that's installed in your development environment.
  2. Back up your database with "drush sql-dump --result-file", since you might have to start over a few times before we're through.
  3. Your code is version controlled, right? If not, I would highly recommend adopting git (learn about git). At the very least, make a backup of your website files now.
  4. If you're using version control, you can create a new testing branch now, or you may use the "develop" branch. Either way, don't push changes to the "master" branch yet. (Here at Mediacurrent, we follow the "git-flow" methodology of version control. We find it a worthy investment for most teams and individuals. Learn about git-flow: Webinar - Git-Flow for Daily Use and Blog - Why Git-flow for my team?

Using drush to update core

  1. Check whether or not your existing core files have been modified from the original (If they have, you may need to apply those changes after updating).
  2. One way to do this (especially if your site lacks documentation describing patch history): download a fresh copy of your version of Drupal core, unpack it into your website directory (overwriting all of your core source files), and use git to check for changes ("git status" and "git diff -- ."). You can find your website's current Drupal version with "drush status".
  3. When you're ready, run "drush up drupal", which will update your codebase to the latest Drupal core, and execute any necessary database updates.
  4. Check for changes to settings.php by comparing sites/default/default.settings.php to sites/*/settings.php. Make sure the only differences are your site configuration.
  5. Check for changes to .htaccess by comparing your original .htaccess to the new .htaccess (with "git diff -- .htaccess"), and copy your modifications (if any) to the new file.
  6. Commit the changes to your git branch.

Using drush to update contrib modules

  1. It doesn't hurt to check a module's release history for any "gotchas" in the upgrade process. Sometimes it's not possible to upgrade between major versions.
  2. Next, determine if the module's source code has been modified on your website. One way to do this (especially if you lack site documentation with patch history): download a fresh copy of the appropriate version ("drush pm-info <module_name>" to get the version installed on your site) from drupal.org, and unpack it into your website's modules directory. This overwrites your existing module files so that you can use "git status" and "git diff -- <module_folder>" to check for modfications.
  3. If it turns out that the module source code on your website has been patched (modified), review the module's drupal.org issue queue to see if the change has been committed to the latest version (if it has been, then you don't need to reapply the patch after upgrading).
  4. If the patch is still needed, check the module's drupal.org issue queue for a re-roll and post one if it hasn't been done.
  5. If you have no patches to apply, run "drush up <module_name>": which updates the module's source code and runs any necessary database updates.
  6. If you have patches to apply, run "drush upc", apply your (re-rolled) patch, and then run "drush updb".
  7. Commit the changes to your git branch.
  8. Repeat steps 1-7 for each module (doing one module at a time makes it easier to undo the changes later).

Regression testing

Let's see what broke! Push your code changes to a testing instance (preferably one that some selected end users can access). If drush is installed in your testing environment, run "drush updb" and "drush cc all". Otherwise, visit "update.php" to execute any pending database updates and "admin/config/development/performance" to clear your caches. Minimum test coverage includes:

  1. Create several nodes of each content type.
  2. Edit several nodes of each content type.
  3. Review all Views, Blocks, Beans, etc. for proper output.
  4. Review several pages for each Panel variant in use.
  5. If you have written custom modules, verify their functionality.

Pushing to production

  1. If you're not using version control, manually back up your production website files now.
  2. If you have version control, push your changes to the "master" branch (best practice: use a tagged release).
  3. Back-up the database (with "drush sql-dump --result-file" if drush is installed on your production instance).
  4. Put your website into maintenance mode.
  5. Update the source code on your production website (git fetch && git rebase origin/master).
  6. Perform any pending database updates (drush updb or visit "update.php").
  7. Clear the caches (drush cc all or visit "admin/config/development/performance").
  8. Verify site functionality, and perform adequate test coverage.
  9. Bring the site out of maintenance mode.
  10. See that all is well, and breathe a sigh of relief for a job well done!

If you practice feature-driven development, upgrading core and contrib often results in changes to the generated feature code. This will cause features that used be in "Default" state to enter "Overridden" state, and you'll want to update your feature code. I always like to review the feature changes ("drush fd <module_name>") before updating the feature code ("drush fu <module_name>").