Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough
Oct 20 2020
Oct 20

Submitted by Dale on October 19, 2020 - 9:13pm

Ansible thoughtsAfter using Ansible as a personal DevOps tool for a couple of months, here are some impressions.

Context

  • Outside of work (web development) I look after six Drupal 7 and WordPress sites on shared hosting
  • My local development is done on a MacBook using apache (with some dabbling in Lando/Docker). I've done some wildcarding with dnsmasq and vhosts to streamline local dev site configuration. CMS code is in git repos.
  • My Ansible work is a personal project and I'm the only stakeholder
  • I learned Ansible doing this work

Ansible Tasks

I'm using Ansible to:

  • backup hosted sites to a local, external hard drive
  • automate sync'ing my local dev site from the production site
  • automate deploying Drupal 7 and WordPress updates using git as the deploy tool
  • automate parts of my WordPress update workflow

Impressions / Observations / Thoughts

In no particular order.

  • I love using the Ansible inventory for host data

    Having a single source for host data is nice. I didn't realize how big an issue/pain point this was until it was solved.

  • Agentless is wonderful
  • Ansible has some unique terminology

    It was initially hard remembering Ansible roles are not a security thing.

  • Maintaining a consistent set of host variables was more work than I thought

    As I iterated writing playbooks and adding or changing host variables, consistently maintaining the variables across hosts became a challenge. I eventually wrote a verification playbook to ensure the required variables existed and had correct values.

  • Documenting really helped

    Writing the verification playbook in turn inspired me to document the host variables. It was more useful than I expected. This inspired me to document other project conventions. Not only did it help consistency, it helped me maintain a high-level view of what I was doing.

  • Single stakeholder is good while learning

    I've done a lot of refactoring as I've learned. I'm happy I started Ansible on a personal project with the luxury to make drastic changes.

  • The console output can be awful

    In many situations the Ansible console output is hard to read or confusing. And there is no easy method to output custom strings to help create understandable output.

  • Thinking about a playbook "wrapper"

    Ansible runs the playbook task list on each specified host and reports by host. For some playbooks it would be nice having a customizable playbook wrapper for better host specifiation and summary reporting. In the greater Ansible world there are web based interfaces with the AWX project and RedHat's Ansible Tower product. Both are overkill for my situation. A shell script will likely be my solution.

  • Not for Drupal 8/9

    Composer and CI/CD tools provide a lot of automation options that don't require learning a new language (a colleague is doing some cool stuff with Robo). So far I don't see Ansible being a better solution, though it could augment a CI/CD workflow in some situations.

Sep 21 2020
Sep 21

Submitted by Dale on September 21, 2020 - 11:55am

Ansible LogoAnsible is an open source IT automation tool. I tend to describe it as a task-runner with a host database (which Ansible calls the inventory). A big selling point is no agent software is needed on managed remote hosts. Details at the Ansible website: https://www.ansible.com/use-cases

tl;dr: If you're just beginning with Ansible this might help: https://github.com/dale42/ansible-starter

I've been experimenting with Ansible for managing a handful of Drupal 7 and WordPress sites I look after. Ansible might be overkill, but this is also a learning project. So far I've been happy with results.

My Ansible learning journey began with small amounts of confusion and frustration. There are lots of different bits to learn. Ansible's file organization is flexible, the examples are data center oriented, and there are multiple syntax styles. This makes many of the examples confusing until the context and details becomes familiar. And I was getting frustrated with file path issues.

As a resource for other new Ansible learners I've created the setup I wish I'd started with. It's at https://github.com/dale42/ansible-starter

Jun 23 2017
Jun 23
#!/bin/bash

# Reinstall a Drupal instance to reset it back to a know state.
# A file base and Drush alias must already be configured.

DRUSH8='/Users/dale/bin/drush8/vendor/bin/drush'
DRUPALDIR='/Users/dale/Sites/group428'
CONFIGDIR='sites/default/group42config/sync'
DRUSHID='@g428'
SITE_NAME='Group 428'
ACCOUNT='admin'
PASS='staring-password'
EMAIL='[email protected]'
DB_URL='mysql://group428:group428@localhost/group428'

# Nuke the database
$DRUSH8 $DRUSHID sql-drop --yes

# Nuke the filebase
echo "Resetting files"
chmod -R u+w $DRUPALDIR/*
rm $DRUPALDIR/sites/default/settings.php
rm -r $DRUPALDIR/sites/default/files
rm -r $DRUPALDIR/$CONFIGDIR

# Fresh Drupal install
cd $DRUPALDIR
$DRUSH8 site-install standard --db-url=$DB_URL --site-name=$SITE_NAME --account-name=$ACCOUNT --account-pass=$PASS --account-mail=$EMAIL --yes

# Base configuration
$DRUSH8 $DRUSHID en admin_toolbar,admin_toolbar_tools --yes

# Allow upcoming changes to settings.php
chmod u+w $DRUPALDIR/sites/default
chmod u+w $DRUPALDIR/sites/default/settings.php

# Configuration Management
sed -i '' "/config\_directories\['sync'\]/d" $DRUPALDIR/sites/default/settings.php
echo "\$config_directories['sync'] = '$CONFIGDIR';" >> $DRUPALDIR/sites/default/settings.php

# Migrate
echo "\ninclude 'settings-migrate.php';" >> $DRUPALDIR/sites/default/settings.php
$DRUSH8 $DRUSHID en migrate,migrate_drupal,migrate_plus,migrate_tools,migrate_upgrade --yes

May 08 2017
May 08

H5PH5P is an open source platform-independent authoring and display system for interactive content. Presentations, quizzes, and other interactive content can be created and displayed using building blocks known as H5P content types (different from Drupal content types). Once a piece of content is created it's easily exported to another H5P system. The development environment is open and well documented, allowing the creation of custom H5P content types.

H5P attributes include:

  • Available in Drupal 7, WordPress, and Moodle
  • Open Source
  • Content is exportable to any other H5P system
  • Uses JavaScript and HTML 5
  • Results tracking for content types such as quizzes
  • xAPI (Tin Can) integration
  • Drupal 7 hook system integration
  • Drupal development environment

Unfortunately there is no Drupal 8 version yet.

There are a variety of H5P content types, including containers such as accordions and sliders which can nest other content types. Some examples are:

  • Arithmetic Quiz
  • Course Presentation
  • Dialog Cards
  • Drag the Words
  • Fill in the Blanks
  • Timeline
  • Interactive Video

The complete list is at https://h5p.org/content-types-and-applications

H5P defines a file packaging format named the ".h5p specification", or simply, H5P file. An H5P file is a zip archive bundling HTML, JSON, JavaScript, and media files. It can contain one or more of a content type, content export, API implementation, application, or JavaScript library.

Drupal Integration

H5P is installed in Drupal in two steps.

  1. Drupal H5P module
    The H5P module is installed using the standard module installation process. It handles the Drupal integration.
  2. H5P Content Types and support files
    H5P content types and the files to support them are installed into a H5P Library manager provided by the H5P module. An H5P archive file of the content types and other support libraries is downloaded from the H5P site and uploaded into the Drupal H5P library.

H5P Content Library

Screenshot of H5P Content Library in Drupal

Content Creation

The Drupal integration contains a H5P node type named, “Interactive content”. When a H5P node is created there is a selector for the H5P content type. For example, quiz, presentation, or dialog card. When a H5P content type is selected the editor for the content type is loaded interactively. The author then creates the desired content.

H5P Content Selector

Screenshot of H5P content type selector

H5P Flashcards content editor

Screenshot of editor for H5P Flashcards content type

Once saved the content is presented when the node is viewed.

H5P Development

The H5P project provides a Drupal development environment (including a developer mode), online documentation, and a forum.

The various specifications and basics for getting started are well documented, and include a “hello world” example. H5P at its heart is JavaScript with a PHP wrapper for integrating with a website. Someone's ability to learn the framework will depend on their comfort with JavaScript.

Coding the editor component that creates and edits the content type typically requires as much work as coding the display for the content type. Custom editor widgets can be written. Existing H5P editor widgets can also be used though they are not documented.

The H5P Drupal hooks provide a clean method of adding CSS stylesheets and modifying H5P behaviour without modifying the base H5P code. Some tasks are complicated by the asynchronous nature of JavaScript loading and the use of iFrames.

Pros and Cons

H5P is continuously changing and improving. These pros and cons are a snapshot of my experience as of May 2017.

Pros:

  • Plug and play interactive content
  • Easy to share content
  • Option for turning off content sharing feature
  • Large variety of content types
  • Open source
  • The H5P team is approachable
  • There is a good content development environment for Drupal
  • The content creators I worked with were able to quickly and easily generate content using H5P
  • Drupal hooks available

Cons:

  • Documentation on some content types is lacking
  • Trial and error is often required to figure out options for some of the sophisticated content types
  • Though some of the content type editors are excellent, some are obtuse or confusing
  • There is no Drupal 8 version
  • Content creators are endlessly creative, you will have to deal with content types being “close but not exactly what I want”
  • There isn't a lot of good guidance on developer workflow if you want to contribute back to the project
  • Staff focused on content creation will probably have favoured tools -- for example, Articulate Storyline -- and push back on an unknown tool such as H5P

Further Reading

May 02 2017
May 02

No more performance anxiety encore!

At our April 2017 meeting Renée Stephen gave the Vancouver Drupal User Group (VanDUG) an encore of her Pacific Northwest Drupal Summit (PNWDS) presentation: No more performance anxiety! The presentation walked us through the formal process of server load testing.

Renée's current gig as Technical Consultant at Acquia gives has given her lots of experience on the subject and she knows how to present. It's always a pleasure when someone deeply steeped in domain knowledge gives a great presentation.

I can't begin to summarize the entire presentation. Renée's slide-deck is available for download at the presentation description on the PNWDS website: No more performance anxiety: get your Drupal site tuned and ready to take the stage! Direct PDF link: PNWDS 2017 - No more performance anxiety.pdf

Here are the take-aways that surprised me:

  • The standard definition of load testing is backend server oriented and does not include front-end performance issues. For example, large hero images or JavaScript widget rendering. While these are important they are not part of this discipline and usually require different tool sets.
  • You'll want at least 2 days, possibly more, to familiarize yourself with jMeter.

I was also reminded of how much server and tool knowledge is required if you're the one doing the remediation. No single detail is exceedingly complicated but each technology in the stack has its particulars, tools, and metics.

Here are the tools Renée mentioned in her presentation:

Profiling Toolkit

  • Blazemeter Recorder
  • Postman
  • HAR
  • jMeter

Dynamic & Static Analysis

  • Blazemeter / jMeter
  • Apachebench (ab)
  • New Relic / TraceView / XHProf
  • WebPage Test
  • Chrome Inspector
  • Server logs and stats
  • varnishstat / varnishlog
  • Redis monitor / memcached-tool
  • Drupal Devel module WebProfiler

She also made a repo of her jMeter example files available at https://github.com/reinette/loadtest

A big thank you to Renée for presenting. I missed the presentation at PNWDS and was happy for the second change to see it.

Nov 17 2013
Nov 17

Customizing the TinyMCE editor's font selection is straight forward thanks to a hook provided by the Drupal Wysiwyg module. The hook_wysiwyg_editor_settings_alter() function allows a module to update the settings passed to the editor. The programming is simple. Discovering and understanding the values of the settings can be a challenge.

Font selection is enabled in the Wysiwyg profile. Edit the profile (Administration > Content authoring > Wysiwyg profiles > Edit) and enable the Font Family dropdown selector by checking the Fonts checkbox in the Button and plugins section. This is as far as the user interface takes us.

Enabling the Font Family dropdown selector

In the TinyMCE initialization code the font selector drop down is configured by a JavaScript string variable named theme_advanced_fonts. The string is a list of font selections with fall backs, separated by semi-collons:

Display name 1=font1,font_fallback1,font_fallback2;Display name 2=font2,fallback_font3, fallback_font4

A real example:

Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde

If the specified fonts are natively available in the web browser no further work is required. If the font is defined using @font-face the definition needs to be in a style sheet loaded by TinyMCE or it will not be displayed during the editing session. The list of stylesheets loaded by the editor is defined in the JavaScript variable named content_css.

Both the theme_advanced_fonts and content_css variables are available in hook_wysiwyg_editor_settings_alter() in a PHP array. In my testing I found the theme_advanced_fonts variable was not pre-populated with the TinyMCE default fonts, even though content_css and other values were. To work around this I pulled the values for theme_advanced_fonts out of the JavaScript configuration file and redefined them in my code.

For the following example the client has declared, "Friends don't let friend's use comic sans, remove it from the list! And please add this font I found on Font Squirrel named Architects Daughter".

In a module for site customizations the hook_wysiwyg_editor_settings_alter() function is defined. This hook fires for all editors so logic is added to specify TinyMCE. The editor fonts are defined in an array to make the list easy to update. In the sample code a line for the Architects Daughter font is added and the line for Comic Sans is commented out. The font list is then assigned to the theme_advanced_fonts variable in the $settings array. The CSS file containing the @font-face definition for Architects Daughter is appended to the content_css variable. This only defineds the font in the editor. The font will also need to be defined for the entire site in the theme CSS.

/**
 * Implements hook_wysiwyg_editor_settings_alter().
 */
function site_customizations_wysiwyg_editor_settings_alter(&$settings, $context) {
  if (
$context['profile']->editor == 'tinymce') {
   
$font_styles = array(
     
"Andale Mono=andale mono,times",
     
"Architects Daughter=architects_daughterregular",
     
"Arial=arial,helvetica,sans-serif",
     
"Arial Black=arial black,avant garde",
     
"Book Antiqua=book antiqua,palatino",
     
/* "Comic Sans MS=comic sans ms,sans-serif", */
     
"Courier New=courier new,courier",
     
"Georgia=georgia,palatino",
     
"Helvetica=helvetica",
     
"Impact=impact,chicago",
     
"Symbol=symbol",
     
"Tahoma=tahoma,arial,helvetica,sans-serif",
     
"Terminal=terminal,monaco",
     
"Times New Roman=times new roman,times",
     
"Trebuchet MS=trebuchet ms,geneva",
     
"Verdana=verdana,geneva",
     
"Webdings=webdings",
     
"Wingdings=wingdings,zapf dingbats",
    );
   
$settings['theme_advanced_fonts'] = implode(';', $font_styles);
   
$settings['content_css'] .= ',' . drupal_get_path('module', 'site_customizations') . '/additional_fonts.css';
  }
}
?>

And the result:

Architects Daughter font

The Wysiwyg profile has a number of CSS options. This code was tested using with Editor CSS set to Use theme CSS. It may be possible to override the content_css value with different settings.

For demonstration purposed I've created an example module named WYSIWYG Fonts and made it available on Github at https://github.com/dale42/wysiwyg_fonts. It is completely self-contained. I recommend copying the code to a site customization or helper module rather than using it as-is.

Jan 08 2013
Jan 08

New versions of websites often have new content organizations with new URL patterns. When old content is assigned a new URL it's almost always desirable to redirect traffic from the content's old URL to its new URL. The redirect preserves external links to the site content (i.e., prevents "link rot") and helps maintain search engine page ranking.

If the Drupal Migrate module is used to create the content for the new site there's an easy code addition for creating the redirect at the same time as the content is created. This method uses the code described in the post: Programatically Create 301 Redirects.

The Migrate framework calls the complete method when an entity, for example a node, is successfully created. Information on the complete method can be found in this documentation: Commonly implemented Migration methods.

The complete method is passed the entity created and the row data used to create it. This provides a place to create a redirect using the Redirect module.

In the following example, the old path is part of the row data. Depending on your situation this information could alternatively come from a pre-generated lookup or separate function call.

class ExampleMigration extends Migration {
 
 
//
  // Migratation code
  //

  /**
   * Definition for Migration complete() method
   */
  </span>function complete($entity, $row) {
   
// Create a redirect from the old path to the new one
   
if (isset($row->old_path)) {
     
// Create an object with our redirect parameters
     
$redirect = new stdClass();
     
$redirect->source = $row->old_path;           // From URL
     
$redirect->source_options = array();
     
$redirect->redirect = 'node/'. $entity->nid// To URL
     
$redirect->redirect_options = array();
     
$redirect->status_code = 0;                   // Redirect Status
     
$redirect->type = 'redirect';
     
$redirect->language = LANGUAGE_NONE;
   
     
// Create the redirect
     
redirect_save($redirect);
    }
  }
 
}
?>

Dec 29 2012
Dec 29

Submitted by Dale on December 28, 2012 - 11:10pm

The Drupal 7 Redirect module gives a site the ability to redirect from one URL to another using a proper HTTP redirect status (e.g., 301 - Permanently moved). In addition to the user interface there is a programmatic method for entering redirects.

The aptly named redirect_save function takes an object containing the details of the redirect and creates a redirect for the URL.

Here is an example of creating a redirect. A status code of 0 uses the default redirect setting which is 301, unless changed in settings.

  // Create an object with our redirect parameters
 
$redirect = new stdClass();
 
$redirect->source = 'the-old-url';     // From URL
 
$redirect->source_options = array();
 
$redirect->redirect = 'node/1';        // To URL
 
$redirect->redirect_options = array();
 
$redirect->status_code = 0;            // Redirect Status, 0 is default
 
$redirect->type = 'redirect';
 
$redirect->language = LANGUAGE_NONE;

  </span>// Create the redirect
 
redirect_save($redirect);
?>

Mar 18 2012
Mar 18

Submitted by Dale on March 17, 2012 - 8:47pm

Like many web types I have a number of small websites I look after, and I've never been happy with my backup solution. Until today.

My requirements are simple, create a backup of the database and files and save it on a local backup drive. The sites don't warrant anything fancy (like a cloud based solution that costs money). The procedure until now involved multiple, fussy steps. It turned out a single script solution is simple once a few key technologies are in place.

Prerequisites

  • SSH no-password/public-key access
    Use your favourite search engine to search on the words: ssh public key authentication for a list of articles on setting up no-password, public-key ssh access. If you don't have public key ability, I suspect the script could be modified to use a password.
  • Drush 4.5 on the host
    If you have root access just follow the drush installation instructions. This article by Robin Monks provided the missing step for my shared-host sites: Installing Drush on a Shared DreamHost Account. The information in this article on setting up an alias, i.e. @site-name, is still valid in drush 4.5: New features in Drush 3

The Backup Script

The backup script uses the drush archive-dump command, available as of drush 4.5, to create a backup tarball that includes the database and files. The backup tarball is scp'ed to the backup drive and deleted from the host.

#!/bin/bash
#
# Backup the Group 42 live site
#
FILENAME=`date "+group42-%Y-%m-%d.tar"`
drush @g42live archive-dump --destination=/home/site/backuptemp/$FILENAME
scp [email protected]:/home/site/backuptemp/$FILENAME /Volumes/Memory-Alpha/Backups/Group42/.
ssh [email protected] rm /home/site/backuptemp/$FILENAME

Four lines of script (plus comments) and whenever I need a site backup it's one done in one command!

Jul 12 2011
Jul 12

AutomationA Drupal upgrade between major versions rarely means doing the upgrade procedure once. A new configuration, changing content, or needing to test different module versions typically means redoing the upgrade from scratch a number of times, a tedious, error-prone and time consuming process. Fortunately there's a solution: automation!

Scripting was always possible, but Drush has made it so much simpler. What follows is a review of the Drush commands I used via script to upgrade my Group 42 website to Drupal 7. The hand full of shell commands are basic and covered many other places on the net. The full upgrade scripts are at the end of the post.

If you're familiar with Drush I recommend jumping directly to the scripts.

Starting Notes

-y / --yes option: This option skips the yes/no confirmation question required by some Drush commands. Since the examples in this post come from scripts this option is shown in the examples.

Drush site aliases: I almost always use a Drush site alias (the "@site-name) parameter, with a command. Some of the commands outlined in this post will only work if you have a site alias. Among other things, it means you can run the command from anywhere.

Drush site-upgrade command: One command you won't find in this post is the Drush site upgrade command. After 20 minutes of trying to use it I gave up. As nearly as I can tell my site wasn't configured the way the command needed it configured. Your results could be different so you'll want to check it out.

Watchdog Log Commands

At various points in the upgrade it's a good idea to check the watchdog log:

drush wd-show

Module Commands

The term module is commonly used to refer to an entire Drupal project even though a typical Drupal project contains more than one module. This can be confusing if the project also has a module with the same name, such as Views. Drush downloads and uninstalls projects, but lists, enables, and disables modules. For example, to remove the Views project in Drupal 6 you disable the Views, Views UI, and Views Export modules, then uninstall the Views project.

Multiple modules can be acted on at once. Examples are shown for both a single and multiple modules.

Listing modules

Drush is an easy way to list installed modules. This is useful for module research lists and creating a list of modules to cut and paste into your script.

For a full summary:

drush pm-list

For a lists all of enabled contributed modules displayed one module per line:

drush pm-list --no-core --type=module --status=enabled –pipe

Downloading Projects

Download the current recommended version of the project:

drush @g42dev dl -y backup_migrate
drush @g42dev dl -y codefilter google_analytics mollom

Download a specific version of the project (required for development versions):

drush @g42dev dl -y cck-7.x-2.x-dev globalredirect-7.x-1.x-dev

Enabling Modules

drush @g42dev pm-enable -y toolbar
drush @g42dev pm-enable -y toolbar overlay shortcut

update.php (Database Updates)

Running update.php using Drush means you don't need to log on as user 1 or use $update_free_access if you forget. Although Drush will tell you if an update error occurred, I like displaying the watch dog log as well.

drush @g42dev updatedb --yes
drush @g42dev wd-show

Disabling Modules

drush @g42dev -y pm-disable backup_migrate
drush @g42dev -y pm-disable views views_export views_ui

Uninstalling Projects

drush @g42dev -y pm-uninstall views 
drush @g42dev -y pm-uninstall admin_menu tagadelic advanced_help

Theme Commands

Themes are enabled and disabled in the same way modules are. You can also set the current theme, administration theme, and theme settings from the Drush command line.

Enable a theme

drush @g42dev -y pm-enable garland

Disable a theme

drush @g42dev -y pm-disable barron

Set the default theme

drush @g42dev -y vset theme_default garland

Set the default administration theme

drush @g42dev vset -y admin_theme seven

Set the theme settings

Theme settings are a bit challenging. In Drupal 7 they're stored as an array. As of writing the current version of Drush could not set arrays with the vset command. However, using the php-eval command it's possible to use the Drupal variable_set() function to set the theme variables.

The following example has been broken into multiple lines for display purposes, but is one, long wrapped line when executed:

drush @g42dev php-eval "variable_set('theme_barron7_settings', array('toggle_logo' => 0,
'toggle_name' => 1, 'toggle_slogan' => 1, 'toggle_node_user_picture' => 0,
'toggle_comment_user_picture' => 0, 'toggle_favicon' => 1, 'toggle_main_menu' => 1, 
'toggle_secondary_menu' => 0, 'default_logo' => 1, 'logo_path' => '',
'logo_upload' => '', 'default_favicon' => 0,
'favicon_path' => 'sites/all/themes/barron7/favicon.ico',
'favicon_upload' => '', 'favicon_mimetype' => 'image/vnd.microsoft.icon'))"

File Copy/Synchronization Commands

If you have your site aliases configured with server and directory information you can save yourself looking up directory paths and rsync paramters by using the built-in Drush rsync:

drush rsync @g42local @g42dev -y

Database Backup/Restore Commands

The Backup and Migrate module also has Drush support, but during an upgrade the module isn't installed.

Database Backup

drush @g42local sql-dump --result-file=/tmp/group42db_d7.sql

Database Restore

It's always best to drop all the database tables before doing a restore, especially during major version upgrades.

drush @g42dev sql-drop --yes
`drush @g42dev sql-connect` < /tmp/group42db.sql

July 13, 2011: Per the comment from dalin, the following syntax is probably better than using the BASH back-tick syntax. If I had known about it I would have used it instead.

drush @g42dev sql-cli < /tmp/group42db.sql

Changing Settings

Many Drupal system and contributed module settings are easily changed using the variable set command. A number of other settings require a direct database update. Since you can easily damage your database doing direct updates I wouldn't recommend using this option unless you know what you're doing.

Site Online / Offline

Since I run my scripts on a development server with no users I don't usually bother with offlining my site. I've included it here because it's easy and something others may want to do in their upgrades.

Whether from Drush or the web administration interface, I've found I need to clear the page cache if it's enabled.

Site Offline

drush vset site_offline 1 --yes
drush cc all

Site Online

drush vset site_offline 0 --yes
drush cc all

Site Information

In the early stages of upgrade testing I'll change my site name and slogan to make my test site easy to tell apart from my production site.

Site Name

drush @g42dev vset --yes site_name "G42 Clone"

Site Slogan

drush @g42dev vset --yes site_slogan "Drupal 7 Upgrade Testing"

Block Position

Since you can corrupt your database with a bad SQL command I wouldn't recommend doing this command unless you're comfortable that you know what you're doing.

drush @g42dev sql-query 'UPDATE {block} SET region = "sidebar_first", status = 1, 
weight = -10 WHERE module = "views" AND delta = "recent_comments-block"'

Path Auto Settings

The tokens used by Path Auto have changed and require updating. Fortunately, they're stored as variables so it's easy to update them by script so you only have to do it once.

drush @g42dev -y vset pathauto_node_story_pattern "[current-page:title]"
drush @g42dev -y vset pathauto_user_pattern "user/[user:name]"
drush @g42dev -y vset pathauto_taxonomy_term_pattern "[term:vocabulary]/[term:name]"
drush @g42dev -y vset pathauto_node_note_pattern "note/[current-page:title]"

I noticed path aliases didn't start working until I saved a node. Perhaps a byproduct of the scripting, or perhaps something else. In any event, this is also easy to do in a script:

drush @g42dev php-eval 'node_save(node_load(6))'

July 13, 2011: The following comment is worth considering if you find yourself in this same situation: http://www.group42.ca/comment/4722#comment-4722.

Path Alias

The default feed URLs for taxonomy terms have changed from /taxonomy/term/n/0/feed to /taxonomy/term/n/feed. There was only one taxonomy term feed I was worried about (Drupal Planet!), so I created an alias for it:

drush @g42dev php-eval 'path_save($a = array("source"=>"taxonomy/term/2/feed", 
"alias"=>"taxonomy/term/2/0/feed"))'

Performance Settings

The performance settings are cache, block_cache, cache_lifetime, page_cache_maximum_age, page_compression, preprocess_css, and preprocess_js. To turn these off for testing:

drush @g42dev vset --yes cache 0
drush @g42dev vset --yes block_cache 0
drush @g42dev vset --yes page_compression 0
drush @g42dev vset --yes preprocess_css 0
drush @g42dev vset --yes preprocess_js 0

The Attached Scripts

The two attached scripts are the actual scripts I used for the Drupal 7 upgrade of this website. They are intended as real-world examples and NOT meant to be prescriptive. Everyone's workflow tends to be different, and these scripts are in service of my workflow. I recommend adapting them to yours. Also, I only loosely followed the upgrade sequence outlined in UPDATE.txt. My upgrade sequence may not work for your site. Take what works for you and leave the rest behind!

In case it's useful, my upgrade workflow was:

  1. Clone the production site as required, either to reset for an upgrade run or to refresh content
  2. Run the upgrade script and test as required
  3. Merge the upgraded file base into the main trunk
  4. Upgrade production site by switching to the new file base and copying the database from the upgrade test site to production site

clonetodev.sh script

This script copies the source website to the upgrade testing site. It's used to reset the upgrade site for repeated testing.

upgrade_d7.sh script

The replacement of Drupal core files is done with a script I describe in this post: Drupal File Upgrade Bash Script.

As I mentioned, this script does not follow the same sequence outlined in UPGRADE.txt. If you use this script as a starting point it's your call whether you maintain the sequence, change it to follow UPGRADE.txt, or adopt a sequence of your own. The nice thing about scripts is it's easy to try different scenarios.

drupalupgrade script

This script is called from upgrade_d7.sh. A full explanation of the drupalupgrade script is in the post: Drupal File Upgrade Bash Script .

Conclusion

I hope the examples prove useful. If you have alternative methods or your own examples I encourage you to share them in your own blog post, the post comments, or in the Drupal.org documentation.

July 21, 2011: Added reference to drupalupgrade script thanks to feedback.

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web