Safe updates ability reference
Reference for the GoBuildWP Pro 1.12.4 source. Installed schemas and policy remain authoritative.
This Safe updates ability reference covers one-at-a-time plugin and theme updates with selected pre/post checks and conditional file recovery. A recent backup is required by default; require_backup=false explicitly bypasses that check. A detected covered failure triggers an attempt to restore the previous files, which may itself fail and does not reverse database migrations or external effects.
Read-only, write and destructive groups describe the source annotations. They do not establish a minimum safety profile, human approval or undo support. Those controls are separate: check the installed ability, the connected user and the active site policy before calling it. A read can still return sensitive data. These pages are not evidence that every operation passed an end-to-end runtime test.
What Safe updates needs before these load
Safe updates ship in GoBuildWP Pro with no vendor gate: WordPress's own upgrader is enough, and the kit declares WordPress 6.9 and PHP 8.0. The backup check reads UpdraftPlus, Duplicator, BackWPup or All-in-One WP Migration through wppilot/backup-status, so one of them should be active. wppilot/safe-update checks that GoBuildWP is switched on, manage_options, update_plugins and update_themes, and needs confirm=true. It also needs a direct filesystem: a site that requires FTP credentials is refused with kit_safe_updates_filesystem, and one with DISALLOW_FILE_MODS with kit_safe_updates_file_mods_disabled.
- Safe updates editions
- free, pro
What safe-update refuses before touching anything
WordPress core (kit_safe_updates_core_refused), GoBuildWP and GoBuildWP Pro themselves (kit_safe_updates_protected), single-file plugins with no directory to copy, items with no download package, usually because a vendor licence is missing (kit_safe_updates_no_package), and versions whose PHP or WordPress requirements the site does not meet. A second update while one is running gets kit_safe_updates_busy.
The backup step wants a successful backup newer than backup_max_age_hours (default 24, up to 720). With no backup plugin the refusal is kit_safe_updates_no_backup_reader; with an old one, kit_safe_updates_backup_stale, which suggests wppilot/backup-trigger. require_backup=false skips the check and is written into the result and history, since the rollback copy restores files and not database changes. If none of the pages to check answers before the update, nothing is changed.
What counts as broken, and what rollback restores
The default pages are the home page plus up to 4 recently modified pages, fetched logged out over loopback, together with the REST index and an admin-ajax heartbeat. The update fails when a page that was fine now returns an error, a fatal or the critical-error page, when the error log shows a fatal from the updated folder, when the version did not rise, or when an active plugin was left inactive. Text changes fail it only above max_text_change.
A page or health check that failed with an error, a fatal or no answer is fetched once more after 8 seconds (steps.recheck), and only what still fails counts: an update whose checks all recover is kept with a reason that starts "recovered on recheck". When a page broke, the rollback reason names the PHP fatal errors the site recorded since the upgrade (GoBuildWP 1.18.5's site issues log), each with its file relative to the WordPress root, line and plugin or theme.
On a LiteSpeed server, LiteSpeed Cache's purge-all resets OPcache, and an ordinary update reaches it through Elementor's cache clear. Since Pro 1.12.3 that purge is held during the update and run once when the safe update is finished, so OPcache does not stay off while the pages are checked. Any other OPcache reset during an update is detected and stated in steps.update.opcache and the reason, because with OPcache off every page can run out of memory for reasons that have nothing to do with the update.
The rollback copy is zipped into uploads/wppilot-kit-safe-updates/ behind deny rules and kept 7 days, so wppilot/rollback-change can undo a successful update within that window. The undo is refused once a later update has replaced the version this one installed.
Inspect the terminal outcome: updated, rolled_back or rollback_failed. Loopback checks do not establish public delivery, logged-in behavior or shop/cart/checkout functionality. Test those separately on staging and retain an out-of-band host/file/database recovery route; neither zero downtime nor complete recovery is guaranteed.
The fresh-backup gate for every other destructive call
Separately from this kit's own check, Pro can refuse any call the free plugin rates destructive or critical unless a successful backup is newer than a set number of hours. It is off by default (wppilot_pro_backup_gate_enabled, hours in wppilot_pro_backup_gate_hours, default 24), refuses with wppilot_pro_backup_gate, and fails closed when no backup plugin can be read. The backup abilities themselves are exempt, and it runs before the approval queue, so a call without a backup is refused rather than parked.
Before accepting the result
Inspect terminal updated, rolled_back or rollback_failed status. A failed restore needs separate recovery; selected probes do not cover database migrations or all visitor flows. require_backup=false is an explicit reviewed exception, not the default procedure.
Representative call sequence
This sequence describes the documented calls and checks to perform. It is not a recorded result from an installed WordPress site. Inspect returned errors and partial results, then verify the saved values and affected output before proceeding.
Plan a staged WooCommerce update with selected checks and a separate checkout test.
- 01
wppilot/updates-availableLists WooCommerce with its current and new version, whether a package is offered and whether safe-update will take it. - 02
wppilot/backup-statusShows when the newest successful backup finished, which decides whether the update would pass its backup step. - 03
wppilot/safe-updateWith confirm=true and selected shop and checkout paths in urls, returns the checks, diff and a terminal outcome of updated, rolled_back or rollback_failed. Test actual cart/checkout interactions separately; fetching a route does not exercise them. - 04
wppilot/rollback-changeIf a problem appears days later, puts the previous version back from the rollback copy using the change_id, within 7 days.
Safe updates in practice
Picking the pages a safe update should test
The checks are only as good as the pages they fetch. By default wppilot/safe-update looks at the home page and the four most recently modified pages, which says little about a plugin that only runs on one template. Pass urls with up to 10 of this site's own pages, as full URLs or paths such as /contact/, and include at least one page where the plugin being updated actually does something: the form page for a form plugin, a product and the cart for a shop extension. An address on another host is refused with kit_safe_updates_foreign_url before anything changes.
Each page is fetched logged out, with a cache-busting query argument and no-cache headers, which makes it much less likely that a page cache answers that a page is fine when PHP can no longer render it. A cache or proxy that ignores both can still answer, so check an important page by hand after the update. Each fetch waits up to 20 seconds, and the first 2 MB of each page is kept for comparison. max_text_change sets a percentage of text change above which the update counts as failed; leave it out and text changes are reported but never trigger a rollback, which suits a plugin whose output legitimately changes between versions.
No screenshots are taken during the update, because a browser cannot run inside the request that is holding the update open. A layout that breaks while the HTML stays valid will not be caught, so compare the important pages by eye afterwards.
When a site cannot run a safe update at all
wppilot/safe-update-history keeps the last 50 runs with their outcome and reason, so it is the place to look when someone asks why a plugin is still on its old version.
- kit_safe_updates_no_loopback (HTTP 409): the site could not fetch its own pages before updating, so the result could not be checked. Nothing changed. Tools > Site Health usually reports the loopback problem.
- kit_safe_updates_busy: another safe update holds the site-wide lock. Updates run one at a time, and a lock older than 15 minutes is treated as left behind by a crashed request and cleared.
- kit_safe_updates_upgrader_failed: WordPress's upgrader reported a failure, and the result carries its last few messages, which are the first place to look for the cause.
Putting an earlier plugin version back days later
A successful update can be reversed with wppilot/rollback-change and its change_id, but two conditions are checked first. If the plugin or theme has been updated again since, the undo stops with kit_safe_updates_updated_since rather than discard that later update; deal with the newer version first. If the rollback copy has passed its seven days and been removed, the result is kit_safe_updates_copy_gone, and the old version has to be reinstalled from the vendor or wordpress.org instead.
Either way, a restore only swaps files. Settings or tables the newer version migrated stay as they are. For a large plugin with its own database changes, the safer return path is the backup the update checked for, restored on staging first; see change ledger and rollback.
Questions about Safe updates
Does a rollback undo database changes the new version made?
No. The rollback copy holds the plugin or theme files. Database migrations the new version ran stay, which is why the backup step exists and why skipping it is recorded.
Can safe-update update a premium plugin?
Yes, when the vendor's updater offers WordPress a download package. When the update is listed but no package is offered, usually because the licence is missing or expired, it is refused with kit_safe_updates_no_package.
Safe updates reads
| Ability | What it does |
|---|---|
wppilot/safe-update-historySafe Update History | Past wppilot/safe-update runs on this site, newest first (the last 50): what was updated, from and to which version, the outcome (updated, rolled_back with the reason the checks failed, or rollback_failed), whether a backup was confirmed or skipped, the ledger change_id, and whether it can still be undone (undo_available, until undo_until: rollback copies are kept 7 days). Filter by target. Changes nothing. |
wppilot/updates-availableUpdates Available | Lists the plugins, themes and WordPress core versions this site has an update for, from WordPress's own update check (refreshed only when older than 12 hours, or with refresh=true). Per item: type, target (plugin file or theme stylesheet, as wppilot/safe-update takes it), current and new version, whether it is active, whether auto-updates are on for it, whether the package downloads from wordpress.org, whether the vendor offers a download at all (premium plugins without a licence do not), PHP/WordPress requirements and compatible, and safe_update with the reason when wppilot/safe-update will not handle it (core, the plugin running it and its companion plugins, single-file plugins). Changes nothing. |
Destructive Safe updates calls
| Ability | What it does |
|---|---|
wppilot/safe-updateSafe Update | Updates ONE plugin or theme (not WordPress core, not the plugin running it) with checks around it, and tries to roll it back automatically when those checks fail; the checks cover only the pages and health requests listed below, and a rollback that itself fails is reported as outcome rollback_failed. Steps, each reported in steps: (1) backup: requires a successful backup newer than backup_max_age_hours (default 24) from UpdraftPlus, Duplicator, BackWPup or All-in-One WP Migration via wppilot/backup-status, else refuses and says how to make one; require_backup=false skips this and is recorded. (2) a zipped rollback copy of the current version. (3) before: each URL (default: home page and up to 4 recently modified pages; urls takes this site's own pages only) fetched logged out over loopback HTTP: status, fatal/critical-error detection, title, text hash; plus the REST index and an admin-ajax heartbeat. (4) the update through WordPress's own upgrader, keeping the plugin active. (5) after: the same checks, plus PHP fatal errors the update's requests logged. (6) diff: fails when a page that worked now returns 5xx, 4xx, a PHP fatal, the critical-error or wp_die page, or no answer; text changes are reported, and fail only above max_text_change percent. A page or health check that failed with an error, fatal or no answer is fetched once more after 8 seconds and only what still fails counts (steps.recheck); when everything recovers the update is kept and reason starts "recovered on recheck:". (7) on failure: the old version is put back, the pages re-checked, outcome rolled_back with the reason, which names the PHP fatal error the site recorded when there is one (file relative to the WordPress root, line, plugin or theme). On success, change_id undoes the update with wppilot/rollback-change for 7 days. Screenshots are not taken (see screenshots). One update at a time per site. Destructive: needs confirm=true. |