Managing multiple WordPress installs with bash and WP CLI

Jump to the bottom if you want to go straight to the script

I recently set up a new VPS on DigitalOcean and chose to manage the web stack and sites with EasyEngine. I’m very impressed with EashEngine, but the fact it makes deploying sites so easy shows up how much overhead there is in staying on top of multiple WordPress installs.

As the recent vulnerability in the REST API showed, keeping on top of updates is really crucial. In the past I’ve used a management system called InifinteWP, but I’ve decided I would rather use fewer tools and instead rely on WP CLI.

The key commands

There are four basic commands key to staying on top of updates:

wp core check-update
wp core update
wp plugin list
wp plugin update --all

They’re self explanatory, and with these you can find out if there are any updates available, and apply them.

Scalability

But logging in to a server, navigating to the web directory, and running potentially four commands is not exactly time saving. Especially when you need to be doing this in a daily basis to ensure critical patches are applied as soon as possible. (Monitoring the vulnerability disclosure lists is a topic for another day.)

Luckily we can easily automate this with a simple bash script with just a few essential steps:

  • find all WordPress installs and loop over them
  • navigate into their directory
  • run the two WP CLI commands needed to check for updates to core and plugins
  • repeat

Once the basics work the script can be easily extended with options such as a choice between checking for updates or doing updates.

EasyEngine hiccups

The standard way of finding a WordPress install so you can use WP CLI is to search for wp-config.php files since you can be certain it exists. Then navigate to the directory where you found it, and execute the command.

However, EasyEngine uses a security conscious directory structure with wp-config.php outside htdocs. This is very sensible, but impacts WP CLI the commands won’t run here – we need to move down into the htdocs directory. One solution is to just add a cd htdocs, but that would mean the script becomes specific to this server setup. Instead, just choose another core file / directory to search for – I went for /wp-admin.

The script

There are many ways this could be extended or customised – but this gist covers the basics and should be flexible enough to cover both EasyEngine and non-EasyEngine setups:

Why ask when you can be told

The last piece of the puzzle is combing the script with cron and mail.

Instead of logging in each day to run the script and check for updates, we can use cron to run it and email the output. This means I can wait for the server to tell me when I need to log in and run an update, and not have to constantly check.

For example, on Ubuntu you can $ sudo crontab -e then add 30 6 * * * su myuser -c '/home/myuser/wp_helper.sh | mail -s "WP Helper update checker" "myuser@domain.co.uk" # run wp_helper.sh at 0630 daily and email.' to run the script at 630 am every day and email the result. Note – this adds the cron job to the root crontab; this means that it will be run as root and so WP CLI will throw a warning. To avoid this su myuser -c runs the command as a chosen user.

I want to review changlogs and test before updating, so am only running the script in check mode. If you are happy auto-updating you could either pass the relevant arguments to the script or use the native WordPress functions.

Category:

7 responses to “Managing multiple WordPress installs with bash and WP CLI”

  1. Yi Liu avatar

    Very nice written script. Thanks for sharing, Phil.
    I adapted one for serverpilot users, shared it on github here:
    https://gist.github.com/liuyigh/34868d44c248d87887c145949e5c164d

  2. Jay avatar
    Jay

    This script would be really useful for me if it could parse a remote list of many servers and connect to them each.

    (I’m looking for a way to bulk change passwords across many servers rather than update WordPress core or plugins.)

    eg: Read list from: https://github.com/org/repo/MyWebsites.txt

    ““
    123.321.00.01
    321.123.00.02
    432.321.00.03
    567.890.00.04

    ““
    and run “wp user update myusername –user_pass=abc123“

    1. Phil avatar
      Phil

      Hi Jay,

      You could look at orchestration tools like Ansible, or else a simple bash script would do it. Something like:
      while read p ; do ssh ${p} ‘cd /var/www/ && wp user update myusername –user_pass=abc123’ ; done

  3. Evan avatar
    Evan

    Great post! Can anyone provide a little help on bash script basics for me? I’d like to understand what lines 21 and 22 do.

    –sites=*)
    SITES=”${i#*=}”

    I’d like to modify the script to work as intended when used with the –sites option. It fails because I’ve got a server with WP installations each stored in their own directory within a “sites” subdirectory. As an example, here are the paths to wp-config.php in three of the sites:

    site1/sites/wp-config.php
    site2/sites/wp-config.php
    site3/sites/wp-config.php

    Thanks!

    1. Phil avatar
      Phil

      Hi Evan

      I’d suggest reading this for a good overview of what it’s doing: https://stackoverflow.com/a/14203146/746692
      In short, 21 tells the script what flag it is processing, then 22 assigns the values from the flag to a variable called SITES.

      Just looking quickly – to handle your `sites` folder, you probably just need a little addition after line 82. On 83 you could try `[ -d sites ] && cd sites` – this should move you into the `sites` folder if it exists.

  4. Raul avatar
    Raul

    Where can I find the script? I did not see a link to it on the article.

    Thanks

    1. Phil avatar
      Phil

      Hi Raul – the embed was broken; fixed now so you should be able to see it again!

Leave a Reply

Your email address will not be published. Required fields are marked *