AIForum.

How to Automate WordPress Tasks with Ollama and WP-CLI

On this page

THE SHORT ANSWER

WP-CLI handles the deterministic WordPress operations, and a local Ollama model supplies the judgement layer that shell scripts lack. This guide shows how to pipe WP-CLI's JSON output into a locally hosted model for plugin-update triage and content drafting, with the safety checks and verification steps that keep automation off your production site until it has earned trust.
Quick facts

You can automate a large part of WordPress maintenance by dividing the work: WP-CLI performs the deterministic operations — listing plugins, applying updates, optimizing tables, creating posts — while a local Ollama model supplies the judgement layer that plain shell scripts lack, such as reading a JSON list of pending updates and ranking which ones are most likely to break a site. The two connect through ordinary pipes and HTTP calls, so no cloud account or API key is involved.

This guide is aimed at technically curious beginners and intermediate practitioners who already have shell access to a WordPress installation. It describes a suggested setup rather than a configuration tested by this publication, and it treats anything that writes to a live site as requiring human review.

Why split the work between WP-CLI and a local model

WP-CLI is a command-line interface for WordPress. Its value in automation is that it is deterministic: the same command against the same database produces the same result, it returns meaningful exit codes, and it can emit machine-readable output with --format=json, --format=csv, or --format=ids. That makes it well suited to scripting.

Ollama runs large language models on your own machine and exposes them through an HTTP API, by default on http://localhost:11434. The model has no knowledge of your particular site; it reasons only over the text you hand it. That limitation is also the point — nothing leaves your server.

Neither half is sufficient alone. A shell script can update every plugin on a schedule, but it cannot read a changelog and notice that one update touches a template your child theme overrides. A language model can produce that judgement, but it cannot be trusted to execute wp plugin update without occasionally inventing a flag or a plugin slug. Splitting the roles keeps destructive actions inside the deterministic tool and fuzzy reasoning inside the model.

The broader claim that a local LLM can handle “virtually every aspect of WordPress management” — core, theme and plugin updates, content generation, database optimisation, security audits, and theme tweaks — comes from a 2025 write-up on About.TomDings.com [1]. That piece is a conceptual position rather than a reproducible test record, so treat it as a description of what is possible, not a measured result. The patterns below are a narrower and more verifiable subset of that vision.

Prerequisites

  • A WordPress installation you can reach over SSH, or a local development copy.
  • WP-CLI installed and available on your PATH. Confirm with wp --info.
  • Ollama installed and running. Confirm with ollama list; if the service is not running, start it with ollama serve.
  • At least one model pulled locally. Any instruction-following model you already have will do; the exact choice is less important than validating its output.
  • jq for parsing JSON. The scripts below use --rawfile, which requires a reasonably recent jq release.
  • A staging copy or a fresh backup. Do not point the first version of these scripts at a production site.

If you have no GPU, small quantised models still run on CPU, but inference is slower and the reliability of structured output tends to drop. Every response should be validated before it is acted on.

Pattern 1: triaging plugin updates

The goal is an ordered list of pending plugin updates, safest first, applied one at a time with a check after each. WP-CLI gathers the facts; Ollama ranks them; the shell applies the result.

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

MODEL="llama3.1"
WP="wp --path=/var/www/html"

# 1. Collect facts with WP-CLI (read-only)
$WP plugin list --update=available 
  --fields=name,version,update_version,status 
  --format=json > /tmp/plugin-updates.json

# 2. Write the instruction block
cat > /tmp/prompt.txt <<'EOF'
You are a WordPress maintenance assistant.
Below is a JSON array of installed plugins with updates available.
Return a JSON object with one key, "order", whose value is an array of
objects with the fields "plugin" and "reason". Sort from the update you
would apply first to the one you would apply last, based on how likely
each update is to break a typical site. Only use plugin names that
appear in the input.
EOF

# 3. Build the request body
jq -n --arg model "$MODEL" 
      --rawfile prompt /tmp/prompt.txt 
      --rawfile context /tmp/plugin-updates.json 
      '{model: $model, prompt: ($prompt + "nn" + $context),
        stream: false, format: "json"}' > /tmp/request.json

# 4. Ask the local model
curl -s http://localhost:11434/api/generate -d @/tmp/request.json 
  | jq -r .response | jq . > /tmp/triage.json

cat /tmp/triage.json

Two details matter here. First, format: "json" asks Ollama to constrain the response to valid JSON, which removes most of the parsing guesswork. Second, the prompt explicitly forbids inventing plugin names — a constraint that is worth restating because a model that hallucinates a slug will cause the next step to fail loudly rather than silently.

Once you have reviewed the ordering by hand a few times, the application step is mechanical:

while read -r slug; do
  echo "Updating $slug"
  $WP plugin update "$slug"
  $WP plugin list --name="$slug" --fields=name,status,version --format=table
  # load the site in a browser, or run your smoke test, before continuing
done < <(jq -r '.order[].plugin' /tmp/triage.json)

The expected observable result is a table showing the plugin at its new version and still active. If a plugin disappears from that table or reports an error status, stop the loop and roll back from your backup or from the previous plugin ZIP.

Pattern 2: drafting content into the review queue

Content generation is a lower-risk use of the same pattern because nothing is published automatically. Pull recent titles with WP-CLI, ask the model for an outline or a first draft, then create the result as a draft post.

$WP post list --post_type=post --post_status=publish 
  --fields=ID,post_title --format=json > /tmp/posts.json

# ... send /tmp/posts.json to Ollama and save the reply as /tmp/draft.html ...

$WP post create 
  --post_title="Draft title here" 
  --post_content="$(cat /tmp/draft.html)" 
  --post_status=draft 
  --porcelain

The --porcelain flag returns only the new post ID, which is convenient for logging. The draft status is deliberate: a local model can produce plausible-sounding prose that is factually wrong, and a human editor remains the checkpoint before publication.

Maintenance tasks that need no model at all

A significant share of routine WordPress upkeep is purely deterministic and gains nothing from an LLM. Wiring these into a cron job or systemd timer is faster, cheaper, and easier to audit than routing them through inference:

  • wp core update and wp core update-db for core releases and schema changes.
  • wp db optimize to reclaim space in MyISAM and InnoDB tables.
  • wp transient delete --expired to clear stale transients.
  • wp post delete $(wp post list --post_type=revision --format=ids) --force to prune revisions.
  • wp core verify-checksums and wp plugin verify-checksums --all to detect modified core or plugin files.
  • wp cron event run --due-now on sites where WP-Cron is disabled in favour of a real system scheduler.

Some commands support --dry-run — wp search-replace is the best-known example — and those should always be run in dry-run mode first. Where a dry run is not available, test against a staging copy.

Safety, limits, and what the evidence does not cover

Several constraints are worth stating plainly.

Never let the model construct a command that you then evaluate. Piping model output into eval or bash -c converts a hallucination into a destructive action. The safe pattern is the one shown above: the model returns data, and your script maps that data onto a fixed allowlist of commands.

Local does not mean private by default. Prompts and responses may be written to logs, shell history, or application data directories. Keep credentials, salts, and customer data out of prompts.

Small models produce malformed output. Even with format: "json", validate with jq and fail closed — if the parse fails, do nothing rather than guessing.

Agent frameworks for WordPress are early. The openclawp project, which builds WordPress-native AI agents on top of Automattic’s agents-api and the AI Client bundled with WordPress 7.0, describes itself as spike-stage software and explicitly warns against running it on a production site. It also notes that it shells out to OS binaries, writes session data to disk, and pairs as a linked device on whichever WhatsApp account you sign in with [2]. That is a useful reminder that the more capable the integration, the larger the blast radius.

Verifying that automation actually worked

  1. Check exit codes. set -euo pipefail at the top of a script stops execution on the first failure.
  2. Re-run the read-only command that produced the input. If wp plugin list --update=available returns an empty array, the updates were applied.
  3. Run wp core verify-checksums after any core or plugin operation to confirm file integrity.
  4. Load the front page, a single post, the admin dashboard, and any page that uses a page builder or form plugin.
  5. Keep a timestamped log file per run. When something breaks three weeks later, the log is the only reliable record of what changed.

Common errors and their fixes

  • curl: (7) Failed to connect to localhost port 11434 — Ollama is not running. Start it with ollama serve, or check the service unit on a Linux host.
  • model "x" not found — the model name in the script does not match anything installed. Run ollama list and use an exact name.
  • jq: command not found — install jq from your distribution’s package manager.
  • Error: This is not a WordPress directory. — WP-CLI was run outside the install root. Use wp --path=/var/www/html or cd into the directory first.
  • The model returns prose instead of JSON — confirm format: "json" is present in the request body, and lower the temperature if your client sends one.
  • wp: command not found in a cron job — cron runs with a minimal PATH. Use the absolute path to the wp binary.

A sensible order of adoption

Start with read-only automation: checksum verification, plugin listing, log collection. Add the model only where judgement genuinely helps, and keep those calls advisory. Move to drafts before you move to updates. Apply updates one at a time on staging for at least a full release cycle before considering production. The value of this combination is not that it removes the operator — it is that it turns a long list of routine decisions into a short list that a human can review in a couple of minutes.

If you try this pattern, the details that matter most to other readers are your environment, the model you used, the exact prompt, and what the output looked like when it went wrong. Sharing those specifics in the community is more useful than a success report.

FAQ

Do I need a GPU to run this workflow?

No, but it helps. Small quantised models run on CPU, though inference is slower and structured output tends to be less reliable. A GPU reduces latency, which matters if the script runs on a schedule.

Is it safe to let a local model apply WordPress updates automatically?

Not unattended. The safe pattern keeps the model in an advisory role — it returns data, and a fixed script maps that data onto specific WP-CLI commands. Apply updates one at a time, on staging first, with a check after each.

Does using Ollama keep my site data private?

Inference happens locally, so prompts are not sent to a third-party provider. However, prompts and responses may still be written to logs, shell history, or application data directories, so credentials and customer data should be kept out of prompts.

Can this run on shared hosting?

Usually not. Both WP-CLI scripting and local model inference assume shell access and enough memory to run a model. A VPS, dedicated server, or local development machine is the more realistic environment.

References

  1. https://about.tomdings.com/fully-automating-wordpress-management-with-ollama/
  2. https://github.com/lezama/openclawp

Related terms

WP-CLI
A command-line interface for WordPress that exposes core, plugin, theme, post, and database operations as scriptable commands with machine-readable output formats.
Ollama
A runtime for downloading and running large language models locally, exposing them through an HTTP API on port 11434 by default.
Structured output
Constraining a model's response to a specific format such as JSON so that downstream scripts can parse it reliably.
Dry run
A mode in which a command reports what it would change without applying the change; supported by some WP-CLI commands such as wp search-replace.
Fail closed
A design principle in which a script stops rather than proceeding when input cannot be validated, such as when a model returns unparseable JSON.

Leave a Reply

Your email address will not be published. Required fields are marked *