From superpowers-sage
Optimizes WordPress performance via Query Monitor profiling, autoload audits, N+1 query fixes, Redis object caching, and frontend improvements like Vite bundles and critical CSS. Use for slow loads, poor Core Web Vitals, or high query counts.
npx claudepluginhub codigodoleo/superpowers-sage --plugin superpowers-sageThis skill uses the workspace's default tool permissions.
- Page load times are slow or degrading
Investigates and optimizes WordPress backend performance using WP-CLI profile/doctor, Query Monitor REST headers, DB queries, autoloaded options, object caching, cron, and HTTP calls.
Analyzes WordPress performance across database queries, PHP execution, frontend rendering, and caching layers. Use when investigating slow pages, optimizing load times, or reviewing caching strategy.
Reviews WordPress PHP code for performance anti-patterns in queries, hooks, caching, AJAX, and templates. Use for auditing themes/plugins, optimizing WP_Query, or diagnosing slow loads/timeouts.
Share bugs, ideas, or general feedback.
# Dump Query Monitor data (pass optional URL, defaults to <dirname>.lndo.site)
bash skills/wp-performance/scripts/query-monitor-dump.sh
bash skills/wp-performance/scripts/query-monitor-dump.sh https://mysite.lndo.site
# Audit autoloaded options (sorted by size, top 20)
bash skills/wp-performance/scripts/autoload-audit.sh
Scripts: scripts/query-monitor-dump.sh · scripts/autoload-audit.sh
Always profile before optimizing. Never optimize blind.
lando wp plugin install query-monitor --activate
If the db.php symlink fails (permissions):
lando ssh -c "ln -sf /app/wp/wp-content/plugins/query-monitor/wp-content/db.php /app/wp/wp-content/db.php"
Key constants (Bedrock config/application.php):
Config::define('QM_DB_EXPENSIVE', 0.05); // seconds threshold for slow queries
Config::define('QM_ENABLE_CAPS_PANEL', true);
See references/query-monitor.md for all panels,
QM timers, custom logging, and how to export data as JSON.
Follow this isolation sequence:
with() queriesQM toolbar shows: page generation time, peak memory, SQL duration, query count.
Enable lazy loading prevention in development:
// app/Providers/AppServiceProvider.php
Model::preventLazyLoading(! app()->isProduction());
Fix with eager loading:
// Bad (N+1)
$posts = Post::all();
foreach ($posts as $post) { echo $post->author->name; }
// Good (2 queries total)
$posts = Post::with('author')->get();
For native WP meta loops:
update_post_meta_cache($postIds); // batch-load all meta in one query
foreach ($postIds as $id) {
$price = get_post_meta($id, 'price', true); // served from cache
}
See references/n-plus-one.md for IN query batching,
ACF block patterns, and full detection workflow.
bash skills/wp-performance/scripts/autoload-audit.sh
Fix oversized options:
lando wp option update <option_name> --autoload=no
Target: total autoloaded size < 500KB.
See references/autoload.md for audit workflow, common plugin culprits, and when to set autoload=no.
lando redis-cli ping # → PONG
Monitor hit rates in QM's Object Cache panel. Target: > 90%.
$posts = wp_cache_get("category-posts-{$id}", 'my-plugin');
if (false === $posts) {
$posts = get_posts(['category' => $id, 'posts_per_page' => 10]);
wp_cache_set("category-posts-{$id}", $posts, 'my-plugin', HOUR_IN_SECONDS);
}
Every cache write requires a documented invalidation strategy. Bust on save_post,
edited_term, or the relevant update hook.
See references/caching.md for transients, Cache::remember(),
full-page caching, and group invalidation.
WHERE, ORDER BY, JOIN$wpdb->prepare() for raw queriesSELECT * — specify columns$wpdb->show_errors() in development only — never in productionlando theme-build -- --analyze # open bundle analyser
const m = await import('./heavy-module.js')manualChunks in vite.config.js| Metric | Target | Common Sage causes |
|---|---|---|
| LCP | < 2.5s | Large hero image, render-blocking CSS, slow TTFB |
| INP | < 200ms | Heavy JS bundle, long main-thread tasks, Livewire hydration |
| CLS | < 0.1 | Images without dimensions, dynamically injected content |
Always declare width and height on images. Preload the LCP image:
<link rel="preload" as="image" href="{{ $heroImageUrl }}" fetchpriority="high">
See references/core-web-vitals.md for full LCP/INP/CLS
remediation, critical CSS with Vite, and third-party script strategies.
Use QM timers for targeted code sections:
do_action('qm/start', 'my-operation');
$result = $this->expensiveComputation();
do_action('qm/stop', 'my-operation');
For call-graph analysis, use Xdebug profiler in Lando:
# .lando.yml
services:
appserver:
xdebug: profile
Trigger: append ?XDEBUG_PROFILE=1 to the URL.
See references/profiling.md for Xdebug setup,
microtime() patterns, and WP hook profiling (pre_get_posts, save_post).
lando wp cron event run --due-nowDISABLE_WP_CRON=true) and use real system cron$wpdb->show_errors() only in development. Never leave error display enabled
in staging or production — it leaks sensitive schema information.wp_cache_set, set_transient, or Cache::remember().$wpdb->show_errors() in production. Use QM logging instead.Model::preventLazyLoading() throws no exceptions)| Symptom | Likely cause | Fix |
|---|---|---|
| TTFB > 1s | No object cache or slow queries | Enable Redis; audit autoloaded options |
| Query count > 50 per page | N+1 or missing eager loading | ->with(), update_post_meta_cache() |
| LCP > 4s | Large unoptimized hero image | Compress, WebP, preload hint |
| CLS > 0.25 | Images without explicit dimensions | Add width/height |
| Redis connection refused | Redis not running in Lando | Check .lando.yml, lando rebuild |
| Object cache not working | Drop-in not installed | Cross-ref acorn-redis skill |
| Stale cached data | No invalidation on update | Add wp_cache_delete to save hooks |
| QM toolbar not visible | Not logged in as admin | Set QM auth cookie via Settings |
| QM db.php symlink missing | Permissions issue | Manually symlink (see Step 1) |
| QM panels empty | QM_DISABLED is true | Check config/application.php constants |
| Slow hooks detected | Expensive callbacks on frequent hooks | Queue async; use QM timers to measure |