Skip to content 99% OFF 🎉 Anniversary Sale 99% OFF Shared Hosting Use Code HURRYUP Claim Offer 99% OFF Hosting
99% OFF Hosting — Code HURRYUP
Products
AI Website Builder New VPS Hosting Cloud Servers Web Hosting cPanel Hosting Dedicated Servers Domains
Company
About Documentation Support Center Contact Get Started Call +91 75795 45488
Login
Hosting Panel — cPanel & Billing Console Panel — VPS Management
ALL SYSTEMS OPERATIONAL
VPS

Update Every WordPress Site on Your Server in One Pass

Getwebup 7 min read

If you're logging into wp-admin on twenty different cPanel accounts every Monday morning to click "Update All," you're spending hours on something a fifteen-line script can do in minutes. Here's how to update WordPress core, plugins, and themes across every site on a WHM reseller account or multi-tenant VPS without breaking anything.

Symptom: Updates Don't Scale Past a Handful of Sites

One WordPress site, wp-admin is fine. Five sites, it's tedious. Twenty or more sites on one server — each with its own cPanel account, its own plugin list, its own PHP version — and manual updates become a part-time job. Agencies and resellers running Getwebup VPS or WHM plans hit this wall fast: you either fall behind on updates (bad, because most WordPress breaches come through outdated plugins) or you burn a full day every week clicking through the same screens on every account.

The fix isn't a plugin that promises to "manage all your sites" from one dashboard — most of those cost more than the time they save and still need per-site babysitting. It's a WP-CLI loop that runs server-side, where you already have root.

Cause: WP-CLI Is Per-Site, Not Per-Server, By Default

WP-CLI is built to operate on one WordPress install at a time — you cd into a directory and run a command. On shared cPanel hosting each account is jailed, so there's no built-in way to fan a command out across accounts. On a VPS or WHM reseller box where you hold root, though, you can script around that jail by looping over every cPanel user and running WP-CLI as that user, one at a time.

The trick is finding each site's real document root reliably — addon domains, subdomains, and multisite installs don't all live in ~/public_html, and guessing wrong either updates the wrong thing or updates nothing silently.

Fix: A Safe, Server-Wide Update Script

Step 1 — List Every cPanel Account and Its Real Docroot

Don't assume public_html. cPanel stores the actual document root for every domain (main, addon, and subdomain) in each account's userdata file. As root:

for user in $(ls /var/cpanel/users); do
  docroot=$(grep -m1 "^documentroot:" /var/cpanel/userdata/$user/main | awk '{print $2}')
  echo "$user -> $docroot"
done

Run that first and just look at the output. If a docroot looks wrong (empty, or pointing at a parked domain with no WordPress install), fix that account manually before it goes anywhere near a loop.

Step 2 — Confirm It's Actually WordPress Before Touching It

Not every account on the server runs WordPress — some might be static sites, Laravel apps, or plain HTML. Check for wp-config.php before running anything:

if su - "$user" -c "test -f $docroot/wp-config.php"; then
  echo "$user is WordPress"
fi

Step 3 — Snapshot Before You Update Anything

This is the step people skip and regret. If you're on a Getwebup VPS, take a snapshot before a bulk run — one command, and you have a full rollback point if a plugin update goes sideways on a dozen sites at once:

# From your VPS control panel, or via the API if you've scripted deployments
# Snapshot first. Always. A bulk update is exactly the scenario snapshots exist for.

On shared/WHM reseller plans without snapshot access, at minimum run a quick per-account backup through cPanel's Backup Wizard, or JetBackup if it's enabled, before the loop runs.

Step 4 — Dry Run First

Before you update anything for real, list what's outdated everywhere, so you know the blast radius:

for user in $(ls /var/cpanel/users); do
  docroot=$(grep -m1 "^documentroot:" /var/cpanel/userdata/$user/main | awk '{print $2}')
  if su - "$user" -c "test -f $docroot/wp-config.php" 2>/dev/null; then
    echo "=== $user ($docroot) ==="
    su - "$user" -c "wp --path=$docroot plugin list --update=available --format=table" 2>/dev/null
  fi
done

Skim this output for anything that looks like a major version jump (say, WooCommerce 8 to 9, or a page builder's major release) — those are the ones you update on a staging copy first, not in the bulk run.

Step 5 — Run the Real Update, One Site at a Time

Update core, plugins, and themes, but keep it sequential rather than parallel. Parallel updates across a dozen sites spike CPU and I/O at the same moment, which is how a bulk update turns into a server-wide slowdown that panics every customer at once:

for user in $(ls /var/cpanel/users); do
  docroot=$(grep -m1 "^documentroot:" /var/cpanel/userdata/$user/main | awk '{print $2}')
  if su - "$user" -c "test -f $docroot/wp-config.php" 2>/dev/null; then
    echo "Updating $user..."
    su - "$user" -c "wp --path=$docroot core update" 2>&1 | tee -a /root/wp-bulk-update.log
    su - "$user" -c "wp --path=$docroot plugin update --all" 2>&1 | tee -a /root/wp-bulk-update.log
    su - "$user" -c "wp --path=$docroot theme update --all" 2>&1 | tee -a /root/wp-bulk-update.log
  fi
done

The log file is what saves you later — when a customer emails three days from now saying their site "suddenly looks weird," you can grep the log for their username and see exactly what changed and when.

Step 6 — Exclude Sites That Shouldn't Auto-Update

Some sites — a client running a heavily customized checkout flow, or one still on an old PHP version because of a legacy plugin — need to opt out. Keep a plain text exclusion list and check against it:

SKIP_LIST="/root/wp-update-skip.txt"
for user in $(ls /var/cpanel/users); do
  grep -qx "$user" "$SKIP_LIST" 2>/dev/null && continue
  # ...rest of the loop
done

Prevention: Automate It, But Watch It

Once the script is solid, cron it — but not blindly:

PracticeWhy it matters
Run weekly, not dailyGives you time to catch a bad plugin update before the next run compounds it
Keep the log file and rotate itYou'll need it the first time a customer disputes what changed on their site
Snapshot or backup immediately before the cron firesA scheduled job with no fresh backup is a scheduled disaster
Email yourself the log summaryA silent cron job is one nobody notices has been failing for a month
Exclude major version jumps from auto-updateCore and security patches are safe to automate; WooCommerce major versions are not
# crontab -e (as root)
0 3 * * 1 /root/wp-bulk-update.sh >> /root/wp-bulk-update-cron.log 2>&1

Running it at 3 AM on a Monday keeps the CPU spike off business hours and gives you the whole week to notice and fix anything before the next run.

Common Pitfalls

  • Running the loop as root without su - user: file ownership on updated plugins ends up owned by root instead of the cPanel user, which then breaks that account's ability to update or edit files through wp-admin afterward.
  • Assuming every account's docroot is public_html: addon domains and subdomains routinely live elsewhere — always read it from /var/cpanel/userdata/ rather than hardcoding a path.
  • No per-site error isolation: if one site's database connection is down, a poorly written loop can stall on that account. Add timeout 300 in front of each wp call so one broken site can't hang the whole run.
  • Updating during business hours: a plugin update that briefly puts a site in maintenance mode is a non-issue at 3 AM and a support ticket at 2 PM.

If you'd rather not maintain this script yourself, Getwebup's managed VPS and reseller plans include scheduled WordPress maintenance as part of support — worth asking about if you're managing more than a handful of client sites on one server.

Frequently asked questions

Will this work on shared cPanel hosting, not just a VPS?

Not directly — shared hosting doesn't give you root, so you can't loop across other accounts on the same server. On shared hosting, WP-CLI still works great per-site through cPanel Terminal, but bulk updates across multiple unrelated accounts need root, which means a VPS or a WHM reseller/dedicated plan.

Is it safe to run wp core update on every site without checking first?

Core updates are generally low-risk since WordPress core is heavily backward-compatible, but plugin and theme updates are where things break. Always dry-run plugin list --update=available first and keep a skip list for sites running customizations that a plugin update could conflict with.

What if a site uses a different PHP version than the server default?

WP-CLI respects the PHP version set for that cPanel account through MultiPHP Manager, so as long as you're running the command as that user (su - user), it picks up the right PHP binary automatically. Running it as root without su can silently use the wrong PHP version.

How do I know if an update broke something across many sites at once?

This is exactly what the log file from Step 5 is for. After a run, grep it for "Error", "Fatal", or "Warning" across all accounts in one pass, so you're not waiting for customers to notice and report it first.

Can I update WordPress multisite networks the same way?

Yes, but target the network root, not each site's URL — run wp core update and wp plugin update --all from the main install's path, since multisite shares one WordPress core and plugin set across all subsites.

#wp-cli #whm #cpanel #wordpress-maintenance #vps #reseller-hosting

Keep reading

Chat with Support