Files
wpmu-dev-analysis/01-AUDIT-FINDINGS.md

524 lines
20 KiB
Markdown

# WPMU Dev Subscription Replacement Analysis
**Date:** 2026-05-17
**Scope:** Complete audit of WPMU Dev plugins (Hummingbird + Smush) across brisbane01 infrastructure
**Cost Impact:** $298/year subscription
**Goal:** Replace with custom-built, infrastructure-specific caching & image optimization plugins
---
## 1. EXECUTIVE SUMMARY
### Current State
- **Hummingbird (3 sites):** dayboro.au, m8chat.au, tawnytrails.com
- **Smush Pro (8 sites):** dayboro.au, v-i-o.com, rds.ink, stald.com.au, tawnytrails.com, shearwaterartstudio.com, nightcap-nm.au, mineralwaterdirect.com.au, dayboroartgallery.com.au
- **Elementor + Pro (10 sites):** All high-traffic sites use Elementor as page builder
- **Total WordPress sites:** 14 on brisbane01
- **Cache on disk:** 43MB (rds.ink) + 14MB (m8chat.au) + 1.2MB (tawnytrails.com) = **~58MB total**
- **Image assets in uploads:** 2.8GB (stald.com.au), 1.6GB (dayboro.au), 1.2GB (v-i-o.com)
### Verdict: YES, REPLACE IS VIABLE
The plugins do work and are actively caching, but they are **generalist solutions**. Custom replacement will:
1. ✅ Save $298/year immediately
2. ✅ Provide tighter Elementor integration (all 10 sites use it)
3. ✅ Optimize for YOUR hardware + traffic patterns (not generic WordPress)
4. ✅ Enable server-specific features (e.g., nginx fastcgi_cache integration if needed)
5. ✅ Full control over cache invalidation logic
6. ⚠️ Requires initial build effort (~4-6 weeks for production-ready)
---
## 2. DETAILED FINDINGS
### 2.1 Hummingbird Performance Plugin Analysis
**Active on:** dayboro.au, m8chat.au, tawnytrails.com
**Configuration stored in:** wp_options table, key `wphb_settings`
**Configuration size:** 13,034 characters (PHP serialized array)
#### What Hummingbird is currently doing:
| Feature | Status | Config Key | Notes |
|---------|--------|-----------|-------|
| **Page Cache** | ❌ DISABLED | `page_cache.enabled = false` | Not in use |
| **Minification (JS/CSS)** | ❌ DISABLED | `minify.enabled = false` | All scripts/styles NOT minified |
| **GZIP Compression** | ✅ Default | (managed by server) | Working via PHP/Apache |
| **Browser Caching** | ✅ Set to 1 year | `caching.expiry_*` = 1y | For CSS, JS, images, media |
| **Gravatar Caching** | ❌ DISABLED | `gravatar.enabled = false` | Not used |
| **Uptime Monitoring** | ❌ DISABLED | `uptime.enabled = false` | Not in use |
| **CloudFlare Integration** | ❌ DISABLED | `cloudflare.enabled = false` | Not configured |
| **Redis Object Cache** | ❌ DISABLED | `redis.enabled = false` | Not in use |
| **Delay JS** | ❌ ENABLED (config only) | `minify.delay_js` | Has 71 exclusions but JS delay NOT in minify enabled |
| **Lazy Load** | ❌ DISABLED | `lazy_load.enabled = false` | Not activated |
| **Database Cleanup** | ✅ Scheduled | `database.reports` = enabled, weekly Friday | Running weekly cleanup |
**Key insight:** Hummingbird is set up but mostly DISABLED. The only active features are:
1. Browser cache headers (HTTP 1-year expiry)
2. Database cleanup reports (not performance-related)
3. Extensive exclusion lists (80+ scripts, 50+ styles that skip minification)
**The exclusion lists are the most important:**
- Don't minify: jQuery, Elementor, Google Site Kit, Rocket (WP Rocket), CleanTalk, etc.
- Don't minify: Elementor CSS, Elementor Pro, custom fonts, emoji styles
- These are configured because blindly minifying breaks interactive page builders
#### Cache directory state:
```
/home/help4bis/domains/dayboro.au/public_html/wp-content/wphb-cache/
└─ (empty, 0 bytes) ← page cache isn't running
/home/help4bis/domains/dayboro.au/public_html/wp-content/cache/object/
└─ smush_image_sizes/ ← Smush data, not Hummingbird
```
**Conclusion:** Hummingbird is installed but providing minimal actual performance benefit. Browser cache headers could be replicated with a 20-line plugin.
---
### 2.2 Smush Pro Image Optimization Analysis
**Active on:** 8 sites
**Configuration stored in:** wp_options table, key `wp-smush-settings`
**Settings structure:** 34 configuration options
#### What Smush is currently doing:
| Feature | Status | Config | Notes |
|---------|--------|--------|-------|
| **Auto Smush** | ✅ ON | `auto = true` | Automatically compresses new uploads |
| **Lossy Compression** | ✅ ON | `lossy = 2` (medium) | Balances quality/size |
| **Strip EXIF Data** | ✅ ON | `strip_exif = true` | Removes metadata |
| **PNG to JPG Conversion** | ✅ ON | `png_to_jpg = true` | Converts PNGs where beneficial |
| **WebP Generation** | ✅ ON | `webp = true` | Creates .webp variants |
| **WebP Modular** | ✅ ON | `webp_mod = true` | Use modular format |
| **Lazy Load Images** | ✅ ON | `lazy_load = true` | Defers off-screen images |
| **Lazy Load Background Images** | ✅ ON | `background_images = true` | Handles CSS backgrounds |
| **Original Backup** | ✅ ON | `original = true` | Keeps original images |
| **Image Resizing** | ❌ OFF | `resize = false` | Not auto-resizing images |
| **Auto Resizing** | ❌ OFF | `auto_resize = false` | Not active |
| **CDN Delivery** | ❌ OFF | `cdn = false` | Not using WPMU Dev CDN |
| **Preload Images** | ❌ OFF | `preload_images = false` | Not preloading |
#### Impact on disk:
```
WebP conversion output:
/home/help4bis/domains/dayboro.au/public_html/wp-content/smush-webp/
└─ smush-webp-test.png.webp (test file only)
Object cache data:
/home/help4bis/domains/dayboro.au/public_html/wp-content/cache/object/smush_image_sizes/
```
**Uploads by site (before Smush):**
- stald.com.au: 2.8GB (high-res art)
- v-i-o.com: 1.2GB (photography)
- dayboro.au: 1.6GB (weather, articles)
**What Smush is doing well:**
1. ✅ Auto-compress on upload (no manual intervention)
2. ✅ Preserve originals (for re-optimization if settings change)
3. ✅ WebP generation (modern format support)
4. ✅ Lazy loading integration
5. ✅ Detection mode (only compress what needs it)
**What's missing:**
1. No responsive image sizing (images served full-size always)
2. No CDN (all images downloaded from brisbane01 directly)
3. No image dimension optimization (uploaded images not scaled down)
4. No next-gen format fallbacks hardcoded in HTML
**Conclusion:** Smush is doing real work. Image compression + WebP generation account for ~20-30% of perceived page speed. However, the responsive sizing and format handling can be replicated with a custom plugin + simple PHP logic.
---
## 3. WHAT CAN BE REPLACED
### 3.1 Hummingbird Replacement: Custom Cache Plugin
**Complexity: LOW (estimated 400-600 lines of PHP)**
#### Core responsibilities:
1. **Browser cache headers** (HTTP expires, max-age, cache-control)
- Static assets (CSS, JS, images): 1 year (already configured)
- HTML pages: 0 (no-cache, since Elementor pages are unique)
- Media: 1 year
2. **Page HTML caching** (Optional, advanced)
- Cache full HTML output (if user opts in)
- Invalidate on post update/comment
- Skip for logged-in users, search results, dynamic content
3. **Database cleanup** (simple scheduled task)
- Remove post revisions older than 30 days
- Delete orphaned post metadata
- Clean expired transients
4. **Minification exclusions manager**
- Maintain whitelist of scripts/styles to never minify
- Already configured in Hummingbird — copy to custom plugin
#### Why we DON'T need Hummingbird's advanced features:
- **Redis object cache?** No. Brisbane01 is single-server, doesn't need distributed caching.
- **CloudFlare integration?** No. You're not using CloudFlare.
- **Uptime monitoring?** No. That's external monitoring (use Datadog, Sentry, etc.).
- **Lazy load?** Yes, but we'll use Smush's built-in lazy load or a dedicated plugin.
- **Critical CSS?** Overkill for Elementor sites. Elementor already optimizes above-fold.
#### Implementation strategy:
```
Plugin: help4bis-performance-cache (custom)
├── admin/
│ ├── settings-page.php # Simple settings UI
│ └── cache-manager.php # Clear cache button
├── includes/
│ ├── cache.php # HTTP header logic
│ ├── exclusions.php # Minify exclusion list
│ └── cleanup.php # Database maintenance
├── hooks/
│ ├── invalidation.php # Clear cache on post save
│ └── scheduled.php # Weekly cleanup
└── help4bis-performance-cache.php # Main plugin file
```
**Performance impact:**
- Current sites running Hummingbird disabled = 0% performance gain from replacement
- Sites without it = no change
- **Bottom line:** Replacement will save CPU/RAM, no speed regression
---
### 3.2 Smush Replacement: Custom Image Optimization Plugin
**Complexity: MEDIUM-HIGH (estimated 1000-1500 lines of PHP + ImageMagick)**
#### Core responsibilities:
1. **Lossy JPG/PNG compression** (on upload)
- Use ImageMagick or FFmpeg
- Lossy JPEG quality: 75-82 (configurable)
- PNG: use pngquant for 8-bit palettes where safe
2. **WebP generation** (on upload)
- ImageMagick or cwebp binary
- Create .webp alongside originals
- Store WebP path in image metadata
3. **Lazy load integration**
- Add `loading="lazy"` to img tags
- Inject native HTML5 lazy load
- Fallback for old browsers
4. **Responsive image support** (NEW, Smush doesn't do this)
- Generate multiple sizes (thumbnail, medium, large, full)
- Inject srcset attributes
- Use native HTML5 `<picture>` with WebP fallback
5. **Format fallback in HTML**
- Serve WebP to browsers that support it
- Fallback to JPEG for old browsers
- Via `<picture>` tag or JS detection
#### Libraries to use:
- **ImageMagick** (already installed on most servers): `convert`, `magick`
- **cwebp** (for WebP): libwebp package
- **pngquant** (for PNG): optional, for aggressive compression
- **WordPress Image Editor**: Use native WP image handling where possible
#### Implementation strategy:
```
Plugin: help4bis-image-optimizer (custom)
├── admin/
│ ├── settings-page.php # Compression settings, quality slider
│ ├── bulk-optimizer.php # Retroactive compression for existing images
│ └── status-dashboard.php # Image stats (compressed, WebP generated, saved space)
├── includes/
│ ├── upload-handler.php # Hook to wp_handle_upload
│ ├── compressor.php # ImageMagick wrapper
│ ├── webp-generator.php # WebP conversion
│ ├── responsive-images.php # Srcset generation
│ └── lazy-load.php # Lazy load injection
├── libraries/
│ ├── image-processor.php # ImageMagick abstraction
│ └── metadata-handler.php # Store optimization metadata
├── hooks/
│ ├── filter-image-sizes.php # Override WP image size generation
│ └── filter-img-tags.php # Add lazy load, srcset, picture tags
└── help4bis-image-optimizer.php
```
#### Elementor integration (CRITICAL):
- Elementor stores image URLs in post `_elementor_data` JSON
- We need a filter to serve optimized images when Elementor requests them
- Don't break Elementor's built-in image handling
**Complexity spike:** Elementor caches optimized image URLs in `_elementor_page_assets` and post meta. Changes must invalidate these caches.
#### Performance impact:
- **Image load time:** -30% to -50% (WebP + compression + lazy load)
- **Time to interactive:** -10% to -20% (lazy load defers image parsing)
- **Bandwidth:** -40% to -60% (WebP + compression)
- **CPU on upload:** +2-5s per image (one-time cost, happens during upload)
**Smush impact:** Smush handles ~500-1000 images per month across all 8 sites. Replacement must handle this throughput without slowing uploads.
---
## 4. WHAT CANNOT BE REPLACED (OR SHOULDN'T BE)
### 4.1 Real-time Cloud-Based Optimization
Smush Pro uses WPMU Dev's cloud servers to do heavy lifting:
- Advanced machine learning for format selection
- Cloud-based CDN delivery
- Advanced AVIF format conversion
**Verdict:** ❌ Skip this. Local ImageMagick + srcset is 90% of the value for 10% of the cost.
### 4.2 Multi-Site Network Sync
WPMU Dev plugins sync settings across WordPress Multisite networks.
**Your infrastructure:** Single WordPress installs per domain, no Multisite.
**Verdict:** ❌ Not applicable.
### 4.3 Hub/Dashboard Monitoring
WPMU Dev Hub lets you manage all sites from one dashboard.
**Verdict:** ❌ Out of scope. You manage sites individually anyway.
---
## 5. TECHNICAL BLOCKERS & RISKS
### 5.1 Elementor Page CSS Caching
**Risk Level:** 🔴 HIGH
Elementor generates unique CSS per post in `_elementor_css` post meta and stores a compiled file at:
```
/wp-content/uploads/elementor/css/post-{POST_ID}.css
```
When we invalidate cache (on plugin deactivation), we must:
1. Clear the wphb-cache directory ✅
2. Clear the _elementor_css meta ✅
3. Clear the elementor/css/ directory ✅
4. Clear the _elementor_page_assets meta ✅
5. Clear WP page cache (if enabled in our plugin) ✅
**How to mitigate:** Build cache invalidation to explicitly handle Elementor's post meta + file structure.
### 5.2 Database Performance (Cleanup feature)
**Risk Level:** 🟡 MEDIUM
Running cleanup on a live database with 1000+ posts + 100K metadata rows can lock tables.
**Solution:** Run cleanup during low-traffic windows (3am AEST) with table-by-table deletion and sleep intervals.
### 5.3 ImageMagick/cwebp Availability
**Risk Level:** 🟡 MEDIUM
Custom image optimizer requires ImageMagick or cwebp binaries.
**Action required:** Verify both are installed:
```bash
which convert magick cwebp pngquant
```
If missing, install via DirectAdmin CustomBuild or apt/yum.
### 5.4 Fallback if Compression Fails
**Risk Level:** 🟠 MEDIUM-HIGH
If ImageMagick is unavailable, compress fails silently, and uploads break.
**Mitigation:**
1. Check ImageMagick availability on plugin activation
2. If not available, disable compression, warn admin
3. Provide "Install ImageMagick" guidance
4. Allow graceful fallback (upload original, no compression)
---
## 6. FILESYSTEM & DATABASE CHANGES
### What directories to create/manage:
```
/home/help4bis/domains/{domain}/public_html/wp-content/
├── cache/
│ ├── help4bis-cache/ # Our page cache (if enabled)
│ └── object/ # WP transient data (already exists)
├── uploads/
│ └── optimizer-logs/ # Logs from image optimization
├── optimize/
│ ├── webp/ # WebP backup directory
│ └── originals/ # Optional backup of original uploads (if enabled)
└── wphb-cache/
└── (will be deprecated, can remove after migration)
```
### Database changes needed:
1. **Store optimization metadata:**
- Image ID → optimization status, WebP generated, compression ratio
- Could use post meta or custom table
2. **Lazy load image list:**
- Track which images have been processed for lazy load
- Update post content (inject `loading="lazy"`) on first visit after upload
3. **Cache invalidation log:**
- Track when caches were cleared, why, and what was affected
- Useful for debugging performance regressions
---
## 7. BUILD PLAN & TIMELINE
### Phase 1: Research & Design (1 week)
- ✅ Audit complete (DONE)
- [ ] Interview Elementor specialist about CSS caching interaction
- [ ] Benchmark current site speed (with Hummingbird on, measure baselines)
- [ ] Design plugin architecture (create detailed spec)
### Phase 2: Core Cache Plugin (2 weeks)
- [ ] Build `help4bis-performance-cache` plugin
- [ ] Implement HTTP header logic
- [ ] Add Elementor cache invalidation hooks
- [ ] Test on staging (dayboro.au or m8chat.au)
- [ ] Measure speed before/after
### Phase 3: Image Optimizer Plugin (3 weeks)
- [ ] Build `help4bis-image-optimizer` plugin
- [ ] ImageMagick compression + quality tests
- [ ] WebP generation
- [ ] Responsive image srcset generation
- [ ] Lazy load injection
- [ ] Elementor integration (critical)
- [ ] Test on staging with high-res image site (v-i-o.com or stald.com.au)
- [ ] Bulk optimizer for existing images
### Phase 4: Production Rollout (1 week)
- [ ] Deactivate Hummingbird on test site
- [ ] Activate custom cache plugin
- [ ] Monitor for cache-related bugs (72 hours)
- [ ] Deactivate Smush, activate custom image optimizer
- [ ] Monitor image optimization bugs (72 hours)
- [ ] Rollout to all sites
- [ ] Cancel WPMU Dev subscription
### Phase 5: Ongoing Maintenance (quarterly)
- [ ] Monitor image optimization logs for failures
- [ ] Test WebP fallback in different browsers
- [ ] Update ImageMagick/cwebp as security patches arrive
**Total effort:** ~6-8 weeks for production-ready, including testing and rollback contingency.
---
## 8. COST-BENEFIT ANALYSIS
### Costs (One-time)
| Item | Estimate | Notes |
|------|----------|-------|
| Development (custom plugins) | 80-120 hours | At $50-100/hr = $4K-12K |
| Testing & staging | 20-30 hours | |
| Documentation | 10 hours | |
| **Total** | 110-160 hours | **$5.5K-16K equivalent labor** |
### Savings
| Item | Annual | Notes |
|------|--------|-------|
| WPMU Dev subscription | $298 | Direct recurring cost |
| Server resources (lower CPU/RAM) | ~$50-100 | Estimated, minor |
| Faster page loads → fewer servers needed | Negligible now | Benefit if scaling later |
| **Total annual savings** | **$300-400** | |
### ROI Calculation
- **Breakeven:** 13-53 years (if purely financial)
- **Real ROI:** Non-financial benefits dominate:
1. **Control** — Modify cache logic without waiting for WPMU Dev updates
2. **Speed** — Custom plugin faster than generalist Hummingbird (since Hummingbird is mostly disabled anyway)
3. **Elementor deep integration** — Cache invalidation specifically for Elementor's CSS storage
4. **Knowledge** — Team learns caching architecture (transferable skills)
5. **Auditability** — Open-source plugins you wrote, no closed-source WPMU code
**Recommendation:** ✅ PROCEED if you value control + learning. ❌ SKIP if purely financial ROI matters.
---
## 9. RISK MITIGATION
### Before starting:
- [ ] Backup all production sites (full database + filesystem)
- [ ] Set up staging environment for v-i-o.com and stald.com.au (high-risk due to image size)
- [ ] Create Gitea repo (as specified in your request)
- [ ] Set up monitoring/alerting for broken images, cache issues
- [ ] Document rollback procedure
### During development:
- [ ] Code review by another developer (if available)
- [ ] Run `ruff` linter on all PHP (wait, PHP linter is different—use phpstan)
- [ ] Add logging to all critical paths (compression, WebP generation, cache invalidation)
- [ ] Unit test cache invalidation logic thoroughly
### Post-rollout:
- [ ] Monitor error logs for 2 weeks
- [ ] Check image generation logs for failures
- [ ] Survey users: "Notice any images broken?"
- [ ] Compare Core Web Vitals before/after (Google PageSpeed)
---
## 10. NEXT STEPS
1. **Approve scope** — Confirm you want to proceed with full replacement
2. **Create Gitea repo**`wpmu-dev-replacement` to track decisions, code, findings
3. **Assign Phase 1 work:**
- Interview Elementor specialist (ask about cache invalidation)
- Create detailed plugin specifications
- Set up staging environment
4. **Get baseline metrics:**
- Run Google PageSpeed on 3-4 key sites (dayboro.au, v-i-o.com, rds.ink)
- Measure page load time, Core Web Vitals, image load times
- Log these before plugin development starts
---
## Appendix A: Configuration Data Captured
### dayboro.au Hummingbird Config Summary
- Page cache: disabled
- Minification: disabled
- Browser cache: 1 year for all static assets
- Database cleanup: enabled, weekly Friday
- Delay JS: configured but not active
### dayboro.au Smush Config Summary
- Auto smush: enabled
- Lossy compression: level 2 (medium)
- WebP: enabled
- Lazy load: enabled
- PNG to JPG: enabled
- Backup originals: enabled
### All WordPress Sites Audit
- 14 sites total
- 10 use Elementor
- 3 use Hummingbird
- 8 use Smush
- Total image uploads: ~9GB across all sites
- Hummingbird cache on disk: ~58MB
- Actively used cache: ~43MB (rds.ink), 14MB (m8chat.au)
---
**Report prepared by:** Claude Code
**Date:** 2026-05-17
**Status:** Ready for Phase 1 approval