Automatic WordPress updates with wp-cli and cron

In this post, I provide instructions on setting up automatic WordPress security updates for multiple sites on UNIX-based servers.

Keeping WordPress up to date is critical for site security, but it can be time consuming if you manage many WordPress sites. There are modules such as Easy Updates Manager to automate the process, but they aren’t always reliable - for example, Easy Updates Manager doesn’t work on sites that also have Wordfence installed. Additionally, Easy Updates Manager needs to be installed and activated on every site.

However, thanks to the magic of wp-cli, it’s possible to update WordPress installations quickly and easily from the command line. Combining this with a cron job, you can set up automatic updates for all of the sites on a server fairly quickly.

First, you will need to install wp-cli. There are fairly comprehensive instructions at https://make.wordpress.org/cli/handbook/installing/. Pick the method most appropriate to your server environment. Bear in mind that if you have multiple sites running as different users, the wp-cli script needs to be accessible to all of them. For this reason, on Debian systems I prefer to use the .deb installation method as it makes the wp-cli executable available to all users at /usr/bin/wp.

Next, I recommend setting up a wrapper script. There are two reasons for this: first, the path to each WordPress install has to be passed to the wp-cli script; second, there are multiple update commands for WordPress core, plugins, themes and languages. This gets quite long-winded in cron format, so I use the wrapper script below. It only requires the path to each install to be passed in, and then it carries out all of the updates. This script is the public domain, so feel free to use it and adapt it to your needs.

#!/bin/sh
# Simple script to update a WordPress install (core, plugins, themes and languages) using wp-cli.
# Usually we expect to run this from cron.
# Written by Kitson Consulting and released into the public domain.

if [ $# -ne 1 ]
then
    echo "Usage: $0 </path/to/wordpress/install>" >&2
    exit 1
fi
if [ ! -d "$1" ]
then
    echo "$1 does not appear to be a directory. Exiting." >&2
    exit 2
fi
if [ ! -f "$1"/wp-config.php ]
then
    echo "$1/wp-config.php does not exist. Did you specify the path to a WordPress install?" >&2
    exit 3
fi
wp core update --path="$1" --quiet
wp plugin update --all --path="$1" --quiet
wp theme update --all --path="$1" --quiet
wp language core update --path="$1"  --quiet
wp language plugin update --all --path="$1" --quiet
wp language theme update --all --path="$1" --quiet

Once you have the wrapper script copied into a suitable location on the server (I recommend /usr/local/bin/wp-update), you are ready to set up the cron jobs. Each cron job uses the following simple command:

/usr/local/bin/wp-update /path/to/wordpress/site

Notes:

  • The cron job should run as the user that owns the website. On many Debian and Ubuntu systems this will be www-data.
  • Make sure that the script wp-update is executable and readable by the cron user.
  • Use the correct full path to the script (/usr/local/bin/wp-update in this example) and the website (frequently /var/www/html).
  • It’s also good practice to make sure that you receive emails from cron, to make sure that you get any notifications about errors. The script is designed to produce no output when it runs successfully, and therefore cron will only send email notifications when an error occurs.

If you have any questions about how to set this up on your own servers, or want to share information about how to use it on different environments, please post in the comments below!

Comments

Hi
I am using WordOps for my VPS to manage WP and the structure like below:

My website is located at /var/www/mywebsite.com/htdocs
the wp-config.php is located at /var/www/mywebsite.com/wp-config.php

I've created the file at /usr/local/bin/wp-update and paste your bash script there, chmod +x for it and set chown is www-data:www-data (correct user:group of the website files).

Put in the crontab command: /usr/local/bin/wp-update /var/www/mydomain.com/htdocs
runs every minute to test.

But no luck, the plugins do not get auto upgrade.

Should I need to your bash script to modify the path to wp-config.php file?

Please advise,
Thanks

Note: Your comment form does not have the email field so how can I get notified if you respond to my comment?

Hi Tom,

You didn't mention whether or not you'd installed wp-cli. That's essential for this update script to work. You also need to make sure that it's executable and that you've used the correct path to it. If you installed it using the .deb file then it will be at /usr/bin/wp and will therefore be in the environment $PATH, but if you installed it by other means then you may need to check that the update script can find it and execute it.

If you've confirmed that and the script still isn't working, you can get extra debugging information in two ways. The first is to tell cron to email you any output when it runs. You do that by adding MAILTO=you@example.com at the top of the crontab. (Obviously substitute in your email address!) This will only work if mail sending is correctly set up on your server, which isn't always the case for web servers.

The second way of debugging is to tell cron to save output to a log file. You'd need to check the log file manually rather than having it emailed to you, but it's more reliable. Change your cron command to something like this:

/usr/local/bin/wp-update /path/to/wordpress/site >> /tmp/wp-update.log 2>&1

The log location needs to writable by whichever user runs the cron job. /tmp is usually writable by all users, although it's not the most secure.

Hope that helps you solve the problem. If you're still stuck and need commercial help, please contact using the link at the top right of the page and we can take a look for you.

P.S. Regarding your question about email notifications, we haven't had time to investigate ways of doing those that aren't open to spam. I've made a note of your comments and will see if we can safely enable notifications in future.

Hi Pete

Thank you for your response.

I confirm that the wp-cli installed at /usr/local/bin

I did add the debug output with your hints and found the problem.

The PROBLEM is my wp-config.php file is not located at the same WP root folder.

Root WP folder: /var/www/mydomain.com/htdocs
wp-config.php file located at: /var/www/mydomain.com

So, if the cron command is /usr/local/bin/wp-update /var/www/mywebsite.com

I get the error:

Error: This does not seem to be a WordPress installation.
Pass --path=`path/to/wordpress` or run `wp core download

if the cron command is /usr/local/bin/wp-update /var/www/mywebsite.com/htdocs

I get the error:

/var/www/turnkeywebsites.net/htdocs/wp-config.php does not exist. Did you specify the path to a WordPress install?

What should I do?

Best regards,
TOM

Hey Tom, I hadn't considered more unusual setups like that when I wrote the wrapper script. The simplest solution is probably to comment out or delete the check for wp-config.php in the wp-update script. It's the third if/fi block. Ideally the script should handle sites that don't follow the basic structure, but that would be quite a lot of extra work. I'll have a think about that for a future version. Hopefully this will let you work around your issue in the meantime. Good luck!

Add new comment