Scripting WordPress upgrades

WordPress has been nagging at me to upgrade. I’m getting more comfortable with shell scripting, and thought that I should script this upgrade process.

I put the script together basically mirroring the manual upgrade instructions given on the WordPress website. I’ll show you the full script, and then walk you through it.

set -e

#Because wget doesn't handle ~ in the prefix
upgradedir=`readlink -f ~/var/wp-upgrade`
upgradefile=$upgradedir/latest.tar.gz
rm -f $upgradefile
wget --directory-prefix=$upgradedir http://wordpress.org/latest.tar.gz
gunzip -t $upgradefile

cp ~/usr/wp-maintenance/.maintenance ~/blog-home/
echo * Site is now down for maintenance *

echo * Backing up files *
tar czf ~/var/backup/blog.$(date +%Y%m%d-%H%M%S).tgz ~/blog-home

echo * Backing up DB *
mysqldump --defaults-extra-file=~/usr/mysql-blog.cnf blog_database | 
  gzip -c > ~/var/backup/blog.$(date +%Y%m%d-%H%M%S).sql.gz

echo * Disabling plugins. Unless you roll back, you will need to enable the plugins manually at the end of this process *
mysql --defaults-extra-file=~/usr/mysql-blog.cnf -e 
  "UPDATE wp_options SET option_value = 'a:0:{}' WHERE option_name = 'active_plugins';" 
  blog_database

echo * The exciting bit - upgrading the installation *
rm -rf ~/blog-home/wp-includes
rm -rf ~/blog-home/wp-admin
tar -xzf $upgradefile -C ~/blog-home/ --strip=1 wordpress/

read -p "* Now re-enable the plugins, and test the site, then press ENTER to exit maintenance mode *"
rm ~/blog-home/.maintenance

echo * Upgrade complete *

The walkthrough:

set -e

Stop if any command returns an error. If anything unexpected happens, I want the script to stop, so I can manually assess and resolve the problem.

#Because wget doesn't handle ~ in the prefix
upgradedir=`readlink -f ~/var/wp-upgrade`
upgradefile=$upgradedir/latest.tar.gz
rm -f $upgradefile
wget --directory-prefix=$upgradedir http://wordpress.org/latest.tar.gz
gunzip -t $upgradefile

Remove any existing copy of the WordPress archive, download the latest version, and test it’s a valid gzip. I assume that if it’s a valid gzip, the TAR file inside will also be okay. The usage of readlink is because when I tried using wget --directory-prefix=~/var/wp-upgrade directly, wget created a directory called ~ inside the directory it was ran from.

cp ~/usr/wp-maintenance/.maintenance ~/blog-home/
echo * Site is now down for maintenance *

.maintenance is a PHP file that with appropriate code will cause a down for maintenance page to be shown when non-admin users visit the site. See the blog post series WordPress Maintenance Mode Without a Plugin for details. ~/usr/wp-maintenance/.maintenance contains the .maintenance code in the third part of the series. I also use a custom down for maintenance page as described in the second part of the series.

echo * Backing up files *
tar czf ~/var/backup/blog.$(date +%Y%m%d-%H%M%S).tgz ~/blog-home

echo * Backing up DB *
mysqldump --defaults-extra-file=~/usr/mysql-blog.cnf blog_database | 
  gzip -c > ~/var/backup/blog.$(date +%Y%m%d-%H%M%S).sql.gz

Create backups of the WordPress directory (~/blog-home) and the WordPress database. $(date +%Y%m%d-%H%M%S) results in the backup files having datetime stamped names.

I’m using a MySQL option file to avoid having to type the database password and also avoid including it in the mysqldump command line. ~/usr/mysql-blog.cnf looks like this.

[client]
host=mysql_host
user=wordpress_database_user
password=wordpress_database_password

[mysqldump]
add-drop-table

Nothing too exciting – the client setting applies to both MySQL commands, the add-drop-table config ensures that drop table statements are included in the MySQL backup.

echo * Disabling plugins. Unless you roll back, you will need to enable the plugins manually at the end of this process *
mysql --defaults-extra-file=~/usr/mysql-blog.cnf -e 
  "UPDATE wp_options SET option_value = 'a:0:{}' WHERE option_name = 'active_plugins';" 
  blog_database

This is taking the risk that WordPress could change the way plugin enabled state is stored in the database, but it’s convenient.

echo * The exciting bit - upgrading the installation *
rm -rf ~/blog-home/wp-includes
rm -rf ~/blog-home/wp-admin
tar -xzf $upgradefile -C ~/blog-home/ --strip=1 wordpress/

Remove the wp-includes and wp-admin directory entirely, and then unzip the new version of WordPress over the old version. The one piece that was tricky here was that the files in the TAR are all in the directory wordpress/, meaning that my first attempt resulted in the creation of ~/blog-home/wordpress. A bit of research found me the --strip parameter, which as used strips wordpress/ from the paths in the TAR.

read -p "* Now re-enable the plugins, and test the site, then press ENTER to exit maintenance mode *"
rm ~/blog-home/.maintenance

echo * Upgrade complete *

Once the operator has confirmed the site is ready for prime time, delete the .maintenance file and make the site available to users again. Job done.