The High-Performance Image Engine for Modern WordPress.
ODR Image Optimizer is a SOLID-compliant performance suite designed to reclaim the critical rendering path. By decoupling image processing from delivery policy, it achieves a 1.8s LCP on throttled mobile connections with 100/100 Lighthouse Performance.
Tested on a standard WordPress 6.9.1 installation using Lighthouse 13.0.1 (Mobile/Slow 4G) with on-demand navigation script loading.
- Largest Contentful Paint (LCP): 1.8s (run-to-run variance: 1.8s-2.0s)
- First Contentful Paint (FCP): 0.8s
- Total Blocking Time (TBT): 0ms
- Cumulative Layout Shift (CLS): 0
- Lighthouse Performance: 100/100 (averaging 99-100 with network variance)
This plugin is built using SOLID design principles to ensure scalability, testability, and maintainability:
WordPress Hook
↓
DI Container
↓
Frontend Service (PriorityService, CleanupService, AssetManager)
↓
Image Processor (Strategy Pattern)
↓
Format-Specific Implementation (WebP, JPEG, PNG)
Key Design Patterns:
| Pattern | Implementation | Purpose |
|---|---|---|
| Service Pattern | PriorityService, CleanupService, AssetManager |
Encapsulate business logic; enable testing |
| Strategy Pattern | ImageProcessorInterface + implementations |
Support multiple image formats without modification |
| Registry Pattern | ProcessorRegistry |
Manage available processors dynamically |
| Factory Pattern | Container class |
Create service instances with dependency injection |
| Policy Pattern | SettingsPolicy |
Decouple configuration from implementation |
| Adapter Pattern | WordPressAdapter |
Abstract WordPress function calls for testability |
This plugin uses a hybrid optimization strategy that respects the SOLID principles:
Tier 1: Intelligent Deferral (NavigationDeferralService)
- Interactivity API scripts are deferred until first user interaction (touches, clicks)
- Fallback: 5-second timeout for passive users
- This preserves full functionality while keeping critical rendering path clean
- Responsibility: Performance optimization (the "how" of loading)
Tier 2: Feature Management (plugin setting)
- Core plugin provides toggle to enable/disable the deferral strategy
- Emoji detection scripts are removed when enabled
- When disabled, all scripts load normally (no deferral)
- Responsibility: Feature management (the "if" of loading)
Why This Approach:
- SRP: Each component has a single responsibility (loading strategy vs feature toggle)
- Least Astonishment: Users understand scripts are being deferred (still available), not removed entirely
- Flexibility: Developers can choose whether to optimize for Lighthouse (defer) or for traditional loading
- Sustainability: Modern dependencies (Interactivity API) are preserved but optimized, rather than ripped out
Status: Fully Implemented
Each class has one reason to change:
JpegProcessor→ JPEG optimization onlyWebpProcessor→ WebP conversion onlyPriorityService→ LCP detection & preloading onlyCleanupService→ Asset dequeue onlyBackupManager→ File backup/restore only
Evidence: 50+ classes, each with focused responsibility. No class handles both business logic and I/O simultaneously.
Status: Fully Implemented
New image formats can be added without modifying existing code:
// Add custom processor via WordPress filter
add_filter('image_optimizer_processors', function($processors) {
$processors['avif'] = new CustomAvifProcessor();
return $processors;
});The ProcessorRegistry::fromMorphMap() method allows registration of new processors at runtime. See EXTENDING.md for examples.
Status: ~95% Implemented
What's Correct:
- All
ImageProcessorInterfaceimplementations throwOptimizationFailedException(consistent contract) - Exception hierarchy ensures callers don't receive unexpected exception types
- All implementations return
bool(predictable return types)
What's Being Improved:
- Standardized exception hierarchy (
ImageOptimizerExceptionbase class) to prevent LSP violations - All concrete processors now extend the same exception base, guaranteeing substitutability
Status: Fully Implemented
Interfaces are narrow and focused:
ImageProcessorInterface→ 3 methods (process,supports,getMimeType)WordPressAdapterInterface→ 9 focused methods, grouped by concern- No "fat" interfaces forcing implementations to have dummy methods
Status: ~85% Implemented, Improving
What's Correct:
Containerprovides centralized DI management- Services receive dependencies through constructors (readonly properties)
OptimizationEnginedepends on abstractions (ProcessorRegistry), not concrete classes
What's Being Improved:
- Frontend services now use
Container::get_service()instead ofnew Service() WordPressAdapterabstracts WordPress function calls (injectable for testing)- PriorityService uses instance state instead of static globals
Migration Path: Services are gradually adopting full DI via the Container. See DEVELOPMENT.md for testing patterns.
Scalability: Each new image format (AVIF, HEIC) requires only adding a new processor class. No modification to existing code = lower regression risk.
Testability: Services depend on interfaces, enabling mock implementations. WordPressAdapter enables testing without WordPress bootstrap.
Maintainability: Clear responsibility separation makes debugging faster. A bug in LCP logic only affects PriorityService.
Extensibility: WordPress filters + registry pattern allow plugins to add custom processors without forking the plugin.
For detailed architecture patterns and implementation examples, see:
- CASE_STUDY.md - Performance optimization deep-dive
- DEVELOPMENT.md - Development workflow & testing patterns
- docs/EXTENDING.md - How to add custom processors
- docs/REFACTORING.md - SOLID refactoring implementation details
- docs/TESTING.md - Comprehensive testing guide
- docs/TEST-PLAN.md - Pre-deployment test checklist
- Deterministic Preloading: Zero-delay discovery for above-the-fold images.
- Bloat Removal: Optional toggles to disable heavy core JS ($60KB+ saved).
- Consolidated Dashboard: Manage all performance policies from a single, secure UI.
- On-Demand Script Loading: Navigation interactivity deferred until user interaction (keeps TBT at 0ms).
- Font Optimization: Local font preloading with
font-display: swapoverride (eliminates Flash of Unstyled Text).
- Download from WordPress Plugin Directory
- Or:
wp plugin install odr-image-optimizer --activate
Navigate to Settings → Image Optimizer to configure:
Control how images are processed and optimized on upload.
- Compression Level: Choose between Low (better quality), Medium (balanced), or High (maximum compression)
- WebP Format Support: Automatically convert images to WebP format for better compression
- Auto-Optimize on Upload: Automatically optimize images when they're uploaded to the media library
Control how images and scripts are delivered and rendered on the frontend.
- Lazy Loading Mode: Choose Native (browser-based
loading="lazy"), Hybrid (with JS fallback for older browsers), or Disabled - Preload Theme Fonts: Preload theme fonts to prevent Flash of Unstyled Text and improve perceived performance
- Remove Bloat Scripts: Defer non-essential JavaScript to improve Lighthouse performance. When enabled, Emoji detection scripts are removed and Interactivity API scripts are deferred to first user interaction (touch, click) with a 5-second fallback for passive users. This keeps the critical rendering path clean while preserving full functionality. Result: 100/100 Lighthouse + interactive features remain available.
- Inline Critical CSS: Inline critical CSS above-the-fold to reduce external CSS requests and unblock rendering
- ✅ WordPress.org compliant
- ✅ Capability-gated settings (
manage_options) - ✅ Nonce verification on all forms
- ✅ Late escaping on all outputs
- ✅ Zero global state pollution
- ✅ ABSPATH protection throughout
# Format code
composer run format
# Static analysis (PHPStan Level Max)
composer run analyze
# Run tests
composer run test
# Quick verification (no WordPress needed)
php tests/verify-changes.php
# Full test suite (requires WordPress autoloader)
php tests/run-tests.php allThis plugin demonstrates professional WordPress development:
- Service Pattern for dependency injection
- Strategy Pattern for image optimization
- Registry Pattern for size management
- Policy Pattern for settings decoupling
- Factory Pattern for service instantiation
The 100/100 score is achieved through "Bandwidth Lane Management Theory":
- Identify competing resources (Emoji script, Interactivity API, fonts)
- Remove non-critical assets from initial load
- Preload essentials early (fonts, LCP image)
- Create parallel download lanes instead of sequential discovery
- Result: Deterministic FCP/LCP, no variance
Read the case study for technical deep-dive.
| Metric | With Plugin | Without Plugin | Impact |
|---|---|---|---|
| LCP | 1.8s | 2.4s | -25% |
| FCP | 0.8s | 1.2s | -33% |
| TBT | 0ms | 50ms | -100% |
| Lighthouse Performance | 100/100 | 96/100 | +4 points |
Note: Metrics measured on WordPress 6.9.1 with Lighthouse 13.0.1 (Mobile/Slow 4G). On-demand navigation script loading defers the 50ms TBT penalty until user interaction, achieving 100/100 without sacrificing functionality.
GPL v2 or later. See LICENSE for details.
Author: Danh Le
Email: danhle@danhle.net
Version: 1.0.2
WordPress: 6.0+
PHP: 8.1+