Files
agent-skills/skills/wordpress-performance-diagnostics/references/fix-patterns.md
T
MalinandClaude Sonnet 5 6fa011a9a6 feat: add wordpress-performance-diagnostics skill
Paired skills.sh/autoskills.sh catalog scans (2026-08-15, reports in
granja/_temp/codex-logs/) independently flagged wordpress/agent-skills'
wp-performance module as the best net-new find of the whole scan: a
measurement-first, backend-only WP diagnostic workflow (WP-CLI
doctor/profile, headless Query Monitor, autoload/object-cache/cron
checks) — a strong fit since this fleet's 13+ WordPress sites are all
headless/jailed with no browser-first profiling access.

Adapted from github.com/wordpress/agent-skills (skills/wp-performance)
rather than installed verbatim: swapped the upstream's local/SSH
assumptions for the fleet's actual `bastille cmd ... su -m www`
remote-execution pattern (reusing wordpress-cli-remote-execution's
convention exactly), added a jail/site selector step against the real
granja/staging/gringo inventory, narrowed the always-collect baseline to
four metrics (TTFB, autoload size, object-cache presence, cron health)
with fleet-specific context for each, added redaction guidance for
Valkey/DB credentials that diagnostic output can surface, and replaced
the upstream's hardcoded "WordPress 7.0+" compatibility claim with
per-site version verification.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 21:26:58 +02:00

5.5 KiB

Fix patterns by bottleneck category

Load this file once references/diagnostic-tools.md (or the Step 3 baseline metrics) has pointed at a dominant bottleneck. Pick one primary category to fix at a time — trying to fix everything in one pass makes the before/after Verification step in SKILL.md meaningless, since you won't know which change caused which delta.

Every fix below is still gated by SKILL.md's Step 0 (read-only-first) and Verification (re-measure the same way afterward) sections.

Database / query performance

Use when profiling points at DB time or a high query count.

  • Avoid N+1 query patterns — batch queries, prime caches, avoid per-row lookups inside a loop.
  • Prefer fields => 'ids' in WP_Query/get_posts() when only IDs are needed.
  • Avoid expensive meta queries where possible; consider indexing or a schema change for genuinely hot lookups.
  • Use object caching for repeated reads (see below) rather than re-querying the same data every request.

Backend-only tools: Query Monitor via REST (query lists, stack traces, slow/duplicate flags) — see diagnostic-tools.md. wp db query for targeted SQL/EXPLAIN — be careful running this in production, it's a direct DB access path.

Query Monitor plugin: https://wordpress.org/plugins/query-monitor/

Autoloaded options

Autoloaded options load on every request, so a large autoload payload hurts every page, not just the page that set the option.

Quick checks (see SKILL.md Step 3 for the always-collect total):

wp option list --autoload=on --fields=option_name,size_bytes | sort -n -k 2 | tail

Fix patterns:

  • Stop autoloading large blobs — store large/rarely-read data with autoload=off instead.
  • Move large computed data to transients or the persistent object cache (if the site has one — check first, see SKILL.md Step 3 metric 3) rather than an autoloaded option.
  • Remove stale options left behind by removed plugins/themes — confirm nothing still reads the option before deleting; a stale-looking option name isn't proof nothing depends on it.

Docs: wp option listhttps://wpcli.dev/docs/option/list · wp doctor's autoload-options-size check — https://make.wordpress.org/cli/handbook/doctor-default-checks/

Object caching

Use when profiling shows repeated identical queries or a low cache hit rate.

  • WordPress's default object cache is per-request memory only — it does not persist across requests unless a persistent drop-in (wp-content/object-cache.php) is present. On this fleet, that's currently only true for menorca.pt/menorca.ro (Redis Object Cache plugin against cerebro's Valkey) — see SKILL.md Step 3 metric 3 before assuming a site has one.
  • wp cache flush (or the Redis-plugin-specific wp redis flush) can affect more than the one site you're working on — cerebro's Valkey DB 0 is genuinely shared across sites by key-prefix, not fully isolated per site (confirmed in docs/server-cerebro.md: wp redis enable's FLUSHDB clears the whole shared DB 0, not just the calling site's prefix). Never flush without explicit approval.

Fix patterns:

  • Cache expensive computed results (transients, or the persistent object cache where one exists) with explicit invalidation — don't rely on natural expiry alone for data that changes on a known event.
  • Avoid unbounded caches — set expirations, or implement real invalidation hooks tied to the data changing.
  • If a site doesn't have a persistent object cache and profiling genuinely points there, adding one is an infra change (provisioning Valkey ACL credentials on cerebro, installing the PHP Redis extension in the jail — package name php85-pecl-redis, not php85-redis, per bastille-jail-provisioning) — coordinate rather than doing it as a drive-by inside a performance investigation.

WP-CLI cache commands: https://wpcli.dev/docs/cache · flush guardrails: https://wpcli.dev/docs/cache/flush

Cron

Use when cron causes request-time spikes or slowness.

wp cron event list
wp cron test           # spawning health
wp cron event run --due-now

Fix patterns:

  • De-duplicate scheduled events and reduce frequency where the task genuinely doesn't need to run that often.
  • Ensure cron callbacks are idempotent and short — a task that's slow enough to matter for site performance is a candidate for moving off the request path entirely, not just running it less often.
  • Move heavy work (imports, RSS/content-agent jobs — several granja sites already run these hourly, per docs/server-granja.md) fully off the page-load request path; a badly-timed spawn on a real WP-Cron pseudo-cron setup can add real latency to whichever request happens to trigger it.

WP-CLI cron command package: https://github.com/wp-cli/cron-command

Remote HTTP API calls

Use when profiling shows slow external requests (wp_remote_get() etc.).

Fix patterns:

  • Add explicit timeouts and fail-fast behavior — a slow or hanging third-party API shouldn't be able to make every page load slow.
  • Cache responses where the data doesn't need to be live on every request (transients / persistent object cache where available).
  • Batch requests, and avoid calling a remote API on every page load when a periodic cron-driven refresh would do.
  • Move genuinely heavy remote work off the request path entirely (cron or a queue), same principle as the Cron section above.

Query Monitor can report HTTP API call timing via the REST envelope (qm property) — see diagnostic-tools.md.