Last active
June 25, 2024 03:23
-
-
Save keesiemeijer/1286ab6695462cf6cf793569c6c356b8 to your computer and use it in GitHub Desktop.
A bash script to update everything WordPress (core, plugins, themes and comments).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# ============================================================================= | |
# | |
# *** WARNING: THIS SCRIPT IS NO LONGER MAINTAINED *** | |
# | |
# use https://github.com/keesiemeijer/wp-update instead | |
# | |
# ============================================================================= | |
# ============================================================================= | |
# DESCRIPTION | |
# | |
# A bash script to update WordPress core, plugins, themes and comments via SSH. | |
# | |
# Features: | |
# All updates are displayed before updating | |
# Interactive prompts keeps you in control of what gets updated | |
# Database and file backups (plugins, themes) are created when updates are made | |
# Manage spam and trash comments | |
# | |
# ============================================================================= | |
# ============================================================================= | |
# REQUIREMENTS | |
# | |
# WP-CLI | |
# SSH access to the server. | |
# | |
# Install WP-CLI if not installed. The command `wp` should be | |
# executable and in your PATH (e.g. /usr/local/bin/). | |
# See the installation instructions for WP-CLI: http://wp-cli.org/#installing | |
# | |
# If you have permission issues when moving it in your Path see https://stackoverflow.com/a/14650235 | |
# ============================================================================= | |
# ============================================================================= | |
# INSTALLATION | |
# | |
# 1 Download this script | |
# curl -o wp-update https://gist.githubusercontent.com/keesiemeijer/1286ab6695462cf6cf793569c6c356b8/raw | |
# | |
# 2 Edit and point the DOMAINS_PATH variable (below this section) to a | |
# parent directory with WP sites in it. | |
# Example: | |
# domains <- point it here | |
# ├── wp-site1 (directory) | |
# │ └── WP files | |
# └── wp-site2 (directory) | |
# └── WP files | |
# | |
# 3 Upload this file to your server and log in with ssh. | |
# | |
# 4 Go to where you uploaded it and make this file executable | |
# chmod +x wp-update | |
# | |
# 5 Move it in your path like you did with WP-CLI (e.g /usr/local/bin/). | |
# If you have permission issues when moving it in your Path see: https://stackoverflow.com/a/14650235 | |
# mv wp-update /usr/local/bin/wp-update | |
# | |
# Now you can use the `wp-update` command to update your sites. | |
# test it out by using "wp-update --help" | |
# ============================================================================ | |
# Edit this variable to point to a directory with WordPress directories in it (see above) | |
readonly DOMAINS_PATH="$HOME/domains" | |
# ============================================================================= | |
# USAGE | |
# | |
# wp-update <site-directory> [option...] | |
# | |
# Use the site directory name for a WordPress site | |
# Use "wp-update --help" to see what options are available | |
# | |
# Without options the plugins and themes are updated. Example: | |
# | |
# wp-update <site-directory> | |
# | |
# The same example, but with options used: | |
# | |
# wp-update <site-directory> --plugins --themes | |
# | |
# Example to update everything | |
# | |
# wp-update <site-directory> --all | |
# | |
# ============================================================================= | |
# ============================================================================= | |
# BACKUPS | |
# | |
# Backups are only created when something is updated. | |
# | |
# Database backups are created before and after updating. | |
# They are saved in the root directory of your website. | |
# Test the backups that are made by this script before you rely on this feature. | |
# | |
# Plugin and theme folder backups are made before updating plugins or themes. | |
# They are saved in the wp-content folder of your website | |
# | |
# Newer backups replace previous backups as not to clutter your website. | |
# ============================================================================= | |
if [ $# -lt 1 ]; then | |
printf "\nUsage: %s <website-directory> [option...]\n" "$0" | |
printf "Example: wp-update my-website --plugins\n\n" | |
printf "Use \"wp-update --help\" to see all options\n" | |
exit 1 | |
fi | |
# ============================================================================= | |
# Variables | |
# ============================================================================= | |
# Website directory | |
readonly WEBSITE=$1 | |
# Does a database backup already exist. | |
DATABASE_BACKUP=false | |
# Do translations need updating (after updating core, plugins or themes). | |
UPDATE_TRANSLATIONS=false | |
# Use a prompt before updating plugins, themes and comments. | |
USE_PROMPT=true | |
# Associative array to check CLI option | |
declare -A OPTIONS | |
# All unique CLI argument options in the right order | |
ALLOPTIONS=() | |
# ============================================================================= | |
# Functions | |
# ============================================================================= | |
function is_file() { | |
local file=$1 | |
[[ -f $file ]] | |
} | |
function is_dir() { | |
local dir=$1 | |
[[ -d $dir ]] | |
} | |
function add_type_option(){ | |
local option=$1 | |
if ! [[ ${OPTIONS["$option"]} ]] ; then | |
OPTIONS["$option"]=1 | |
ALLOPTIONS+=("$option") | |
fi | |
} | |
function maybe_do_database_backup(){ | |
if [[ "$DATABASE_BACKUP" = true || "$DATABASE_BACKUP" = 'none' ]]; then | |
return 1 | |
fi | |
if ! make_database_backup "before"; then | |
printf "Creating a database backup before updating failed" | |
exit 1 | |
fi | |
return 0 | |
} | |
function make_database_backup(){ | |
local prefix=$1 | |
if is_file "${prefix}_update_${WEBSITE}.sql"; then | |
printf "Removing a previous database backup file...\n" | |
rm "${prefix}_update_${WEBSITE}.sql" | |
fi | |
printf "Creating a backup of the %s database ${prefix} updating...\n" "$WEBSITE" | |
wp db export "${prefix}_update_${WEBSITE}.sql" --allow-root | |
if ! is_file "${prefix}_update_${WEBSITE}.sql"; then | |
printf "\e[31mWarning: No database backup file found in: %s\033[0m\n" "$DOMAINS_PATH/$WEBSITE" | |
return 1 | |
fi | |
if ! [[ -s "${prefix}_update_${WEBSITE}.sql" ]]; then | |
printf "\e[31mWarning: database backup file is empty in: %s\033[0m\n" "$DOMAINS_PATH/$WEBSITE" | |
return 1 | |
fi | |
DATABASE_BACKUP=true | |
return 0 | |
} | |
function wp_core_is_installed(){ | |
# Check for wp-config.php file | |
if ! is_file "wp-config.php"; then | |
return 1 | |
fi | |
# Check if WP tables exist | |
wp core is-installed --allow-root 2> /dev/null | |
} | |
function update_wp_core(){ | |
printf "Checking WordPress version...\n" | |
update=$(wp core check-update --field=version --format=count --allow-root) | |
if [[ -z $update ]]; then | |
printf "WordPress is at the latest version\n" | |
return 0 | |
fi | |
maybe_do_database_backup | |
printf "Updating WordPress\n" | |
wp core update --allow-root | |
UPDATE_TRANSLATIONS=true | |
} | |
function update_language(){ | |
printf "Checking translations...\n" | |
update=$(wp core language list --update=available --format=count --allow-root) | |
if [[ $update = 0 ]]; then | |
printf "No language updates available\n" | |
return 0 | |
fi | |
maybe_do_database_backup | |
printf "Updating translations\n" | |
wp core language update --allow-root | |
} | |
function update_asset(){ | |
local asset_type=$1 | |
local update | |
printf "Checking %s updates...\n" "$asset_type" | |
update=$(wp "$asset_type" list --update=available --number=1 --format=count --allow-root) | |
if [[ $update = 0 ]]; then | |
printf "No %s updates available\n" "$asset_type" | |
return 0 | |
fi | |
printf "Updating %ss\n" "$asset_type" | |
if [[ "$USE_PROMPT" = true ]]; then | |
wp "$asset_type" update --all --dry-run --allow-root | |
read -p "Do you want to update all ${asset_type}s [y/n]" -r | |
if ! [[ $REPLY = "Y" || $REPLY = "y" ]]; then | |
printf "%s updates aborted\n" "$asset_type" | |
return 1 | |
fi | |
fi | |
printf "backing up %ss\n" "$asset_type" | |
if is_file "$DOMAINS_PATH/$WEBSITE/wp-content/${asset_type}s-backup"; then | |
rm -rf "$DOMAINS_PATH/$WEBSITE/wp-content/${asset_type}s-backup" | |
fi | |
cp -r "$DOMAINS_PATH/$WEBSITE/wp-content/${asset_type}s" "$DOMAINS_PATH/$WEBSITE/wp-content/${asset_type}s-backup" | |
maybe_do_database_backup | |
printf "Updating %ss\n" "$asset_type" | |
wp "$asset_type" update --all --allow-root | |
UPDATE_TRANSLATIONS=true | |
return 0 | |
} | |
function update_comments() { | |
local status=$1 | |
printf "Checking %s comments...\n" "$status" | |
count=$(wp comment list --number=1 --status="$status" --format=count --allow-root) | |
if [[ $count = 0 ]]; then | |
printf "No %s comments found\n" "$status" | |
return 0 | |
fi | |
if [[ "$USE_PROMPT" = true ]]; then | |
wp comment list --status="$status" --fields=ID,comment_author,comment_author_email,comment_approved,comment_content --allow-root | |
read -p "Do you want to delete all ${status} comments [y/n]" -r | |
if ! [[ $REPLY = "Y" || $REPLY = "y" ]]; then | |
printf "Deleting %s comments aborted\n" "$status" | |
return 1 | |
fi | |
fi | |
maybe_do_database_backup | |
printf "Deleting %s comments\n" "$status" | |
wp comment delete $(wp comment list --status="$status" --format=ids --allow-root) --allow-root | |
return 0 | |
} | |
# ============================================================================= | |
# Options | |
# ============================================================================= | |
while test $# -gt 0; do | |
if ! [[ "$1" =~ ^- ]]; then | |
# Not starting with a dash (not an option). | |
shift | |
else | |
case "$1" in | |
-h|--help) | |
printf "\nwp-update usage:\n" | |
printf "\twp-update <website-directory> [option...]\n\n" | |
printf "wp-update example:\n" | |
printf "\twp-update my-website --plugins\n\n" | |
printf "Options controlling update type:\n" | |
printf -- "\t-w, --core Update WordPress core\n" | |
printf -- "\t-p, --plugins Update plugins\n" | |
printf -- "\t-t, --themes Update themes\n" | |
printf -- "\t-l, --translations Update translations\n" | |
printf -- "\t-c, --comments Update comments\n" | |
printf -- "\t-a, --all Update everything\n\n" | |
printf "\tWithout an update type option plungins and themes are updated\n\n" | |
printf "Options extra:\n" | |
printf -- "\t-h, --help Show help\n" | |
printf -- "\t-f, --force Force update (without a prompt to abort updating (themes, plugins, comments)\n" | |
printf -- "\t-x, --no-db-backup Don't make a database backup before and after updating\n\n" | |
exit 0 | |
;; | |
-f|--force) USE_PROMPT=false ;; | |
-x|--no-db-backup) DATABASE_BACKUP='none' ;; | |
-w|--core) add_type_option "core" ;; | |
-p|--plugins) add_type_option "plugins" ;; | |
-t|--themes) add_type_option "themes";; | |
-l|--translations) add_type_option "translations" ;; | |
-c|--comments) add_type_option "comments";; | |
-a|--all) add_type_option "all" ;; | |
*) | |
printf "Unknown option: %s. Use \"wp-update --help\" to see all options\n" "$1" | |
exit 1 | |
;; | |
esac | |
shift | |
fi | |
done | |
# Check if options is empty | |
if [[ ${#ALLOPTIONS[@]} -eq 0 ]]; then | |
ALLOPTIONS=("assets") | |
fi | |
# Check if `all` was used | |
if [[ ${OPTIONS["all"]} ]]; then | |
ALLOPTIONS=("all") | |
fi | |
# ============================================================================= | |
# Start updates | |
# ============================================================================= | |
if ! is_dir "$DOMAINS_PATH/$WEBSITE"; then | |
printf "Could not find Website directory: %s\n" "$WEBSITE" | |
exit 1 | |
fi | |
cd "$DOMAINS_PATH/$WEBSITE" || exit | |
if ! wp_core_is_installed; then | |
printf "No WordPress website found in: %s\n" "$DOMAINS_PATH/$WEBSITE" | |
exit 1 | |
fi | |
# Check network connection for options that need it. | |
if [[ ${OPTIONS["all"]} || ${OPTIONS[plugins]} || ${OPTIONS["themes"]} || ${OPTIONS["core"]} || ${OPTIONS["translations"]} ]]; then | |
printf "Checking network connection...\n" | |
if ! ping -c 3 -W 5 8.8.8.8 >> /dev/null 2>&1; then | |
# Bail if there is no internet connection | |
printf "No network connection detected\n\n" | |
exit 1 | |
else | |
printf "Network connection detected\n" | |
fi | |
fi | |
for type in "${ALLOPTIONS[@]}" | |
do | |
case "$type" in | |
assets) | |
update_asset "plugin" | |
update_asset "theme" | |
;; | |
core) | |
update_wp_core | |
;; | |
plugins) | |
update_asset "plugin" | |
;; | |
themes) | |
update_asset "theme" | |
;; | |
comments) | |
update_comments "spam" | |
update_comments "trash" | |
;; | |
all) | |
update_asset "plugin" | |
update_asset "theme" | |
update_wp_core | |
update_comments "spam" | |
update_comments "trash" | |
;; | |
*) | |
if ! [[ 'translations' = "$type" ]]; then | |
printf "Unknown option: %s. Use \"wp-update --help\" to see all options\n" "$type" | |
exit 1 | |
fi | |
esac | |
done | |
# Translations are updated at the end (if needed) | |
if [[ "$UPDATE_TRANSLATIONS" = true ]]; then | |
update_language | |
else | |
if [[ ${OPTIONS["translations"]} ]]; then | |
update_language | |
fi | |
fi | |
if [[ "$DATABASE_BACKUP" = true ]]; then | |
if ! make_database_backup "after"; then | |
printf "Creating a database backup after updating failed" | |
exit 1 | |
fi | |
fi | |
printf "Finished updating\n" |
Hi @locougil
I've moved this script to a github repo, and I'm not maintaining this script anymore.
https://github.com/keesiemeijer/wp-update
You can loop through directories with a one-liner like this.
for d in path/to/directory/*/ ; do wp-update "$d"; done
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi,
Thanks a lot for your work, it's working perfectly ;)
Is it possible to loop through all the site directories and update all the sites in one command line ?
like wp-update --all and it will update suball the sub directories from the variable readonly DOMAINS_PATH="$HOME/domains" ?
Hope to hear from you soon
Kind regards
Loïc