DEV Community

Cover image for How often to update WordPress plugins and themes, and how to roll back when it breaks
AumCreate
AumCreate

Posted on

How often to update WordPress plugins and themes, and how to roll back when it breaks

There is no single correct interval. What keeps a site both patched and working is a fixed cadence, a fixed order of operations, and a rollback you have already tested. Here is the schedule I would put on a calendar, and exactly what happens inside the maintenance window.

The cadence

What How often Where it runs
Anything whose changelog says security fix within 24-72 hours production, straight after a backup
Routine plugin updates once a month, same day, same hour staging first, then production
Plugins that touch money (payments, checkout, tax, shipping) once a month, staging plus a test order staging first, always
Major version bumps (the first number changes) once a quarter, batched staging, changelog read line by line
Theme updates quarterly, or when there is a fix you actually need staging; customisations live in a child theme
WordPress core security and minor releases as released production
WordPress core major releases quarterly, after staging staging first
Cleanup once a quarter delete deactivated plugins you do not use

Two things this table is deliberately not saying.

First, "turn on auto-updates for everything" is not a cadence. It is a decision to have changes happen at an hour you did not choose, on a site you are not watching. Auto-update is defensible for small, single-purpose, security-relevant plugins. It is not defensible for anything that renders pages or takes money.

Second, "update whenever the dashboard turns orange" is also not a cadence. It means updates get applied in the ten minutes before a demo, which is the worst ten minutes available.

The 15-minute weekly check

Once a week, look, do not update:

  • Are there updates flagged as security releases? Those jump the queue.
  • Is anything still on the list from last month because you skipped it? Skipping twice is how a plugin ends up three major versions behind and un-updatable.
  • Has anything been abandoned? No release in a long time, support threads unanswered, and it is still active. That is a replacement project, not an update.

Everything else waits for the monthly window.

Before the window: pre-flight

Do these five things in order. If any of them fails, the window is cancelled.

  1. Confirm the site works right now. Load the homepage, submit a form, log in. You need a known-good baseline to compare against, and "it was already broken" is a sentence you do not want to say afterwards.
  2. Note the current state of the error log. Tail the PHP error log and the web server error log. Anything already in there is not caused by the update - write the count down so you can tell new noise from old noise.
  3. Back up, and prove the backup is readable. A backup you have not opened is a hope. More on this below.
  4. Write down what is installed. Plugin and theme names plus their current state, so you can pin things back.
  5. Read the changelogs for the plugins you are about to update. You are looking for three things: a required PHP or WordPress version higher than yours, a line containing "breaking change" or "database", and a jump in the first number of the version.

The backup

#!/usr/bin/env bash
set -euo pipefail

SITE=/var/www/example
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
DEST=/backups/$STAMP
mkdir -p "$DEST"

# 1. Database
wp db export "$DEST/db.sql" --path="$SITE"

# 2. Only the trees updates actually touch
 tar -czf "$DEST/wp-content.tar.gz" -C "$SITE" \
  wp-content/plugins wp-content/themes

# 3. Inventory, so you can pin back later
wp plugin list --path="$SITE" --format=csv > "$DEST/plugins.csv"
wp theme list  --path="$SITE" --format=csv > "$DEST/themes.csv"

# 4. Prove the archive opens before you need it
tar -tzf "$DEST/wp-content.tar.gz" > /dev/null
echo "backup ok: $DEST"
Enter fullscreen mode Exit fullscreen mode

Three details that make the difference between a backup and a decoration:

  • Store it off the server. A backup sitting next to the site disappears with the site.
  • Record the timestamp in the change log, because in a panic nobody remembers which backup is the right one.
  • Restore it once, on staging, before you need it in anger. A restore you have never performed is a hypothesis.

Order of operations inside the window

Update one thing at a time and look at the site between each step. Batches hide the culprit.

  1. Deactivated plugins: delete, do not update. An inactive plugin is attack surface with no benefit.
  2. Low-risk utility plugins first - admin tweaks, log viewers, things the front end does not depend on.
  3. Content and marketing plugins next - SEO, forms, redirects. Check the front end after this step.
  4. Anything touching money last among plugins - payments, checkout, tax, shipping. Immediately run a test order in the gateway's sandbox mode.
  5. Theme last among the code. If the parent theme ships customisations you edited directly, the update will erase them. That is the moment to move those edits into a child theme, not after.
  6. WordPress core major releases after everything else, never in the same window as a theme rewrite.

If a page builder is in play, update the builder and its addons in the same window. Updating the builder today and the addons next week is how you get the half-broken layout that takes three days to diagnose.

After each step, purge cache

Object cache, page cache, and CDN, in that order. A stale object cache after an update produces bugs that do not exist in the code, and you will spend an hour chasing them.

The smoke test

Run the same list every time, in the same order:

  • Homepage loads, no PHP warnings printed.
  • One page built with the page builder renders correctly.
  • A form submits and the submission actually arrives somewhere.
  • Checkout completes with a sandbox test order.
  • Login works, including the password reset email.
  • Search returns results.
  • One product or post page renders.
  • The site looks right at mobile width.
  • The error log has no new lines since step 2.

Rolling back: three levels

Pick the smallest level that fixes the problem. Most incidents stop at level one.

Level 1 - files only

Use when: the plugin broke rendering, threw a fatal error, or started a redirect loop, and it did not change your database.

SITE=/var/www/example
STAMP=20260115T030000Z   # the backup from before the update
PLUGIN=broken-plugin

wp plugin deactivate "$PLUGIN" --path="$SITE"
rm -rf "$SITE/wp-content/plugins/$PLUGIN"
tar -xzf "/backups/$STAMP/wp-content.tar.gz" -C "$SITE" "wp-content/plugins/$PLUGIN"
wp plugin activate "$PLUGIN" --path="$SITE"
Enter fullscreen mode Exit fullscreen mode

Why not just reinstall the plugin from the directory? Because the directory serves the current release. The only reliable copy of the version you were running is the folder you saved before updating. This is the single strongest argument for keeping the pre-update archive.

Level 2 - files and database together

Use when: the update ran a migration - created tables, changed columns, converted content - and the old code will not work against the new schema.

SITE=/var/www/example
STAMP=20260115T030000Z

# Save the current state first. You are about to lose everything since the export.
wp db export "/backups/emergency-$(date -u +%Y%m%dT%H%M%SZ).sql" --path="$SITE"

# Then restore files and database together.
rm -rf "$SITE/wp-content/plugins/broken-plugin"
tar -xzf "/backups/$STAMP/wp-content.tar.gz" -C "$SITE"
wp db import "/backups/$STAMP/db.sql" --path="$SITE"
Enter fullscreen mode Exit fullscreen mode

Say the cost out loud before you do this: a database restore also rolls back orders, form submissions, comments, and posts created after the export. Take the emergency export first, then work out what needs to be re-entered. Restoring files without the database, or the database without the files, leaves you with a mismatched site that fails in new and creative ways.

Level 3 - full restore from a host snapshot

Use when: the site is down, the admin is unreachable, and you cannot get a shell in fast enough to do level 1 or 2 by hand. This is the slowest and bluntest option. It works, and it costs you everything written since the snapshot.

Roll back or fix forward?

Symptom Do this
White screen, fatal error, admin unreachable roll back now, debug on staging
Layout broken on some pages roll back, then check builder/addon pairing
Checkout or form broken roll back immediately, then investigate
A deprecation notice in the log, site works fine fix forward, do not roll back for noise
New feature has a bug, vendor already shipped a patch fix forward
New feature has a bug, no patch, site works wait, do not roll back a working site
Plugin migrated data and then broke roll back files and database together, level 2

Two rules of thumb. Roll back when the site is losing money or is unreachable. Fix forward when the only symptom is a log line and the functionality works.

Traps worth writing on the wall

  • Testing on staging with the live payment gateway. Use sandbox mode, or you will test the payment flow by charging a real card.
  • Forgetting the staging URL rewrite. After importing production into staging, run a search-replace from example.com to staging.example.com with a dry run first. Skip it and you will be clicking links back into production.
  • Updating during a campaign, a launch, or a Friday afternoon. The window exists for a reason.
  • Editing the parent theme directly. The next theme update deletes your work with no warning and no undo. Child theme, always.
  • Updating a plugin that nothing else depends on, then leaving it untested for a month. The bug report arrives when nobody remembers what changed.
  • Never removing anything. A site with forty plugins, twelve of them deactivated, is harder to update, harder to back up, and harder to reason about.
  • Skipping the same update three months in a row. The eventual jump is bigger and riskier than three small ones would have been.

The whole process on one page

  • Weekly: look for security releases and abandoned plugins. Do not update.
  • Monthly, in a fixed window: back up, verify the backup, note the error log baseline, update one at a time from lowest risk to highest, purge cache, run the smoke test, write the change down.
  • Quarterly: major version bumps on staging first, theme review, delete what you do not use, restore a backup to prove it still works.
  • During an incident: roll back the smallest thing that fixes it, then debug on staging with the broken version pinned.

That is the entire discipline. It is boring, it takes about an hour a month, and it is the difference between a patch you applied and an outage you caused.

Top comments (0)