Aditya Sharma

AI

Automating WordPress maintenance with agents: what is worth automating and what is not

On this page, 10 sections

Run the integrity check that every WordPress maintenance guide recommends on a site with twelve plugins, five of them commercial, and this is the shape of what comes back.

The message strings, the counting and the exit code are from the WP-CLI source, which I read on 2 September 2026.

The plugin names and the counts are an illustration:

The WordPress integrity check exits zero on the plugins it never checked.
  • --dry-run shows what would change and changes nothing.
  • --patch is the narrowest bar that still ships security fixes.
  • --minor takes minor releases and holds back majors.
  • --exclude takes everything except the plugins the whole site is built on.
$ wp plugin verify-checksums --all
Warning: Could not retrieve the checksums for version 5.9.2 of plugin acme-pro, skipping.
Warning: Could not retrieve the checksums for version 3.1.0 of plugin acme-forms, skipping.
Success: Verified 7 of 12 plugins (5 skipped).
$ echo $?
0

Exit code zero. Five plugins were never checked.

If your automation branches on the exit code, and most automation does, that site just passed an integrity check that examined fifty-eight per cent of its plugin code.

Why the exit code is zero

Seven plugins verified, five skipped, on a site with twelve installed.
Built from the run at the top of this post. Message strings, counting and exit code read from the WP-CLI source on 2 September 2026.

That is not a bug. The command downloads checksums from WordPress.org, and commercial plugins are not on WordPress.org, so there is nothing to compare against.

The handling in Checksum_Plugin_Command.php, in wp-cli/checksum-command, is four lines: when $checksums comes back false it calls WP_CLI::warning() with that skipping message, increments $skips, and continues.

And in report_batch_operation_results() in WP-CLI core, skips only affect the wording. A skip appends ({$skips} skipped) to the message.

When there are no outright failures the function calls WP_CLI::success(), which exits zero. Only the failures branch calls WP_CLI::error(), and that is the branch that exits non-zero.

The shape of the problem

The exit code is zero even after five plugins were never checked.
wp plugin verify-checksums –all, then echo $?. WP-CLI source read 2 September 2026.

This is the shape of almost every honest answer about automating WordPress maintenance. The task is automatable.

The thing you wanted to know is one layer behind the output, and an agent that reads only the summary line will confidently tell you the site is fine.

The split I actually use

Everything below assumes the agent has wp-cli over SSH and read access, set up the way I described in running Claude Code against WordPress, and the credential limits from the guardrails post.

The split is not about capability. An agent can run every command here. It is about which decisions have bounded consequences.

TaskAutomate?Why
Gathering update, integrity and cron stateYesRead-only, and the output is what a human needs to decide
Reading changelogs and classifying riskYesLanguage work with a written artefact you can check
Detecting file drift against WordPress.orgYes, with the skip caveat handledDeterministic comparison
Post-change verification sweepsYesCheap, repeatable, catches the thing you did not think of
Deciding whether to apply a major updateNoUnbounded consequence on a page-builder site
Fleet-wide scheduled updatesNo, use a fleet toolAlready solved, with rollback and reporting you would rebuild badly
Restoring a backupNoOne shot, and the failure mode is losing the good copy
Cleaning a compromised siteNoRequires knowing what normal looked like before
Renewing or dropping a plugin licenceNoCommercial decision with a client attached

Worth automating: the state-gathering pass

This is the highest-value thing an agent does with a WordPress site, and it is entirely read-only.

One script, one JSON blob, and the agent reasons over it instead of running twenty commands and losing the earlier output to context pressure.

Mine runs six things and prints one object.

  • wp plugin list --format=json --fields=name,status,update,version, and the same for wp theme list.
  • wp core check-update --format=json, falling back to an empty array when it writes nothing.
  • wp plugin verify-checksums --all, with stdout and stderr sent to two different files, because the warnings are the finding.
  • wp core verify-checksums --include-root, which is the one that reports files sitting in the WordPress root that do not belong to WordPress.
  • A count of the skip warnings: grep -c 'skipping\.$' over the warning file, stored as plugins_not_verifiable.
  • One jq -n call that slurps the three JSON files and the count into a single object keyed by site.

The one field that changes behaviour

The field that changes behaviour is plugins_not_verifiable.

Any number above zero means the integrity check has a hole in it exactly the size of your commercial plugins, which are also the plugins most likely to have been nulled, patched by hand, or installed from a marketplace that is not the vendor.

Feed that number to the agent and tell it to treat a non-zero value as a finding rather than a footnote.

The root-file check nobody runs

The other half of that gap is wp core verify-checksums --include-root, which warns about files in the WordPress root that do not belong to WordPress.

That is a genuinely useful signal and it is one of the few automated checks that would have caught the situation I wrote about when a scanner reported a site clean while it served spam to Googlebot.

Worth automating: update triage, which is not the same as updating

The distinction that makes this safe: the agent produces the plan, a human approves it, then the agent executes the approved plan. WP-CLI gives you four flags to do that properly.

wp plugin update --all --dry-run
wp plugin update --all --patch
wp plugin update --all --minor
wp plugin update --all --exclude=elementor,elementor-pro

--dry-run, --patch, --minor and --exclude are all documented options on wp plugin update.

The --exclude flag is the one that turns this from a gamble into a policy: the plugins your layout depends on go on the exclusion list permanently and get handled by a human with a staging copy.

Where the agent earns its keep

Where the agent earns its keep is the layer above the flags.

Given the dry-run output, it can pull each plugin’s changelog, sort the updates into security, bug fix, feature and breaking, and tell you which three of the eighteen you actually need to think about.

That is language work with a written artefact you can check, which is the shape of task agents are reliably good at.

Do not stack an agent on a broken auto-update setup

If auto-updates are meant to be handling this and are not, that is a separate diagnosis with its own set of causes, and I have written it up in fixing WordPress automatic updates that are not working.

Do not stack an agent on top of a broken auto-update setup and assume the agent is the fix.

Worth automating: the verification sweep after a change

Updates rarely fail loudly. They fail by turning one template into a blank section, or by dropping a widget that only appears on the pricing page.

The check is boring, repeatable and exactly what you should hand to a machine.

Capture the status code and the byte size of every page that matters before the update, do it again after, then join the two files and print any row where the status changed or the size dropped below ninety per cent of what it was.

What this catches and what it does not

Byte size within ten per cent is a crude proxy and it will produce false positives on anything with a rotating element.

It also catches the failure that matters most, which is a page that still returns 200 while rendering a fraction of its content.

Pair it with a real render check on a handful of templates and you have covered most of what goes wrong.

Not worth automating: the update go/no-go on a site you did not build

The mechanism is worth stating plainly, because it explains several of the rows in that table at once.

Retrievable evidence against evidence that is nowhere

An agent is good at tasks where the evidence is retrievable and the consequence of being wrong is a bad paragraph.

It is bad at tasks where the evidence lives in a place nothing can query.

Whether a major update to a page-builder addon breaks a client’s homepage depends on which of forty widgets that homepage uses, which of them the addon rewrote, and whether the site has custom CSS targeting the old markup.

None of that is in the changelog. Some of it is not written down anywhere.

So the agent gathers, classifies and recommends. A human with the site open decides. On sites where a broken layout means a phone call, that division has never felt like a limitation to me.

Not worth automating: the fleet update loop, because it already exists

This is the part where I will argue against building the thing.

If you manage twenty client sites, the job of pushing updates across them with a rollback point, a per-site log and a report the client can read is a solved problem, and the solutions have had years of edge cases beaten out of them.

Where the fleet tools actually differ

I have run the feature comparisons across this category in detail. The short version of where the differences actually land:

The arrangement that works

The useful pattern is not agent instead of fleet tool.

It is the fleet tool doing the mechanical push, and the agent doing the reading and the reporting that the fleet tool does not do: reading changelogs, correlating an error spike with a specific update, drafting the client-facing note.

The commercial side of that arrangement, including who pays for which licence, is its own conversation and I covered it in managing WordPress plugin subscriptions for clients.

Not worth automating: restores, and cleanups

A restore is one shot with an unbounded downside. The realistic failure is not a wrong command, it is a right command against the wrong snapshot, and by the time anyone notices, the good copy has been written over. A human runs restores.

Why cleanup is worse than a restore

Cleaning a compromised site fails for a different reason. Removing malware requires knowing what the file was supposed to contain, and on a site with a decade of plugins and a hand-edited theme, nothing has that baseline.

wp core verify-checksums gives it to you for core. wp plugin verify-checksums gives it to you for WordPress.org plugins and, as established at the top, silently gives you nothing for the rest.

An agent asked to clean a site with an incomplete baseline will delete things that were supposed to be there.

What the agent can do in an incident

What the agent can do in an incident is collect evidence fast: modified file timestamps, the checksum diff, admin users created in the last month, scheduled events that do not belong to any installed plugin, and the raw access log lines around the first modified file.

That is a triage pack, and it makes the human faster without giving the machine a delete button.

The WP-CLI command reference page for wp plugin verify-checksums.
developer.wordpress.org/cli/commands/plugin/verify-checksums/, screenshot taken 3 September 2026.

The one number to check on your own fleet this week

Run this on every site you maintain:

wp plugin verify-checksums --all 2>&1 \
  | grep -c 'skipping\.$'

That count is how many plugins on that site have no integrity baseline at all.

Not how many are compromised. How many you could not tell either way. On most agency fleets it is not zero, and until now the number was probably invisible because the command exited zero and printed the word Success.

The fix is a policy

Once you have the number, the fix is a policy rather than a script: keep a known-good copy of every commercial plugin zip you install, checksum it yourself at install time, and compare against that.

It is the same idea WordPress.org gives you for free, applied to the half of your site that WordPress.org does not cover.

If you are doing this across client sites, the process side matters as much as the tooling, and how to manage WordPress websites for clients covers how I structure that.

And if you want the underlying detail on what an agent can reach over HTTP rather than over SSH, including why there is no plugin update route in core at all, that is in the post on the REST API as an agent surface.

Resources

Disclosure: I am CMO at POSIMYTH, which ships WordPress plugins across 500,000+ installs, and our commercial plugins are exactly the kind that verify-checksums skips. That is the honest reason I know the gap is there.

More on agents on wordpress

Tell me where I am wrong

Your email is not published and I do not add it to any list. Corrections with a source are the ones I act on fastest.