-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathodr-image-optimizer.php
More file actions
309 lines (276 loc) · 12.3 KB
/
odr-image-optimizer.php
File metadata and controls
309 lines (276 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
<?php
declare(strict_types=1);
/**
* Image Optimizer Plugin
*
* @package ImageOptimizer
* @author Danh Le
* @license GPL v2 or later
* @link https://danhle.net
*
* @wordpress-plugin
* Plugin Name: ODR Image Optimizer
* Plugin URI: https://github.com/odanree/odr-image-optimizer
* Description: Professional high-performance image suite. Features SOLID-compliant WebP conversion, intelligent LCP preloading, and automated critical path cleanup for a 100/100 Lighthouse score.
* Version: 1.0.7
* Author: Danh Le
* Author URI: https://danhle.net
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: odr-image-optimizer
* Domain Path: /languages
* Requires at least: 6.0
* Requires PHP: 8.1
* Tested up to: 6.9
* Stable tag: 1.0.7
* Tags: images, performance, webp, lcp, speed, optimizer
*/
// If this file is called directly, abort.
if (! defined('ABSPATH')) {
exit('Direct access denied.');
}
// Define plugin constants with ODR_ prefix for WordPress.org compliance
define('ODR_IMAGE_OPTIMIZER_VERSION', time()); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
define('ODR_IMAGE_OPTIMIZER_PATH', plugin_dir_path(__FILE__)); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
define('ODR_IMAGE_OPTIMIZER_URL', plugin_dir_url(__FILE__)); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
define('ODR_IMAGE_OPTIMIZER_BASENAME', plugin_basename(__FILE__)); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
// Include the autoloader
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/class-autoloader.php';
// Register the autoloader
\ImageOptimizer\Autoloader::register();
// Manually include core classes to ensure they're loaded
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/interface-optimizer.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-result.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-optimizer-config.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-resizing-config.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-image-file.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-image-context.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-tool-registry.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-container.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-permissions-manager.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-database.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-media-transformer.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-image-resizer.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-resizing-processor.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-optimizer.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-optimizer-contract-validator.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-dip-audit.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-hook-contract-validator.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-isolation-audit.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-permission-enforcement-audit.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-hook-complexity-analyzer.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/core/class-api.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/Services/class-size-selector.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/Services/class-size-registry.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/Services/class-layout-policy.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/Services/class-header-manager.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/Services/class-asset-manager.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/Services/class-priority-service.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/Services/class-cleanup-service.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/Services/class-navigation-deferral-service.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/admin/class-settings-service.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/Frontend/class-responsive-image-service.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/Frontend/class-frontend-delivery.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/Frontend/class-webp-frontend-delivery.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/admin/class-dashboard.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/admin/class-settings-policy.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/admin/class-settings.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/Frontend/WebpDelivery.php';
require_once ODR_IMAGE_OPTIMIZER_PATH . 'includes/Frontend/ResponsiveImages.php';
/**
* The main plugin class
*/
use ImageOptimizer\Core;
use ImageOptimizer\Core\API;
use ImageOptimizer\Services\SizeRegistry;
/**
* Initialize custom image size registry early
*
* Register custom image sizes (odr_mobile_optimized, odr_tablet_optimized)
* that bridge the gap between mobile and desktop breakpoints.
*/
add_action(
'after_setup_theme',
function () {
$registry = new SizeRegistry();
$registry->register_optimized_sizes();
// Hook custom sizes into srcset calculation
add_filter('wp_calculate_image_srcset_meta', [ $registry, 'add_to_srcset' ]);
},
);
/**
* Initialize REST API early
*/
add_action('rest_api_init', function () {
$api = new API();
$api->register_routes();
}, 1);
/**
* Activate the plugin
*/
register_activation_hook(__FILE__, [ Core::class, 'activate' ]);
/**
* Deactivate the plugin
*/
register_deactivation_hook(__FILE__, [ Core::class, 'deactivate' ]);
/**
* Initialize WebP delivery early (plugins_loaded)
*/
add_action('plugins_loaded', function () {
// Initialize WebP delivery FIRST - needs to hook early
new \ImageOptimizer\Frontend\WebpDelivery();
// Initialize responsive images
new \ImageOptimizer\Frontend\ResponsiveImages();
}, 1);
/**
* Initialize the plugin
*/
add_action('init', function () {
Core::get_instance();
}, 20);
/**
* Register plugin settings (admin only)
*/
add_action('admin_init', function () {
$settings_service = new \ImageOptimizer\Admin\SettingsService();
$settings_service->register();
});
/**
* Add plugin admin menu
*/
add_action('admin_menu', function () {
add_submenu_page(
'image-optimizer',
'Performance Toggles',
'Performance Toggles',
'manage_options',
'odr-optimizer',
function () {
?>
<div class="wrap">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<p>Toggle performance optimizations for mobile Lighthouse testing and A/B analysis.</p>
<form action="options.php" method="post">
<?php
settings_fields('odr_optimizer_group');
do_settings_sections('odr-optimizer');
submit_button();
?>
</form>
</div>
<?php
},
);
}, 20);
/**
* Initialize performance optimizations (before content renders)
*
* Uses DI Container to manage service lifecycle.
* Runs at template_redirect (early, before wp_head) to detect LCP and apply optimizations.
*/
add_action('template_redirect', function () {
if (! is_admin()) {
// Detect LCP image ID early (before wp_head)
$priority_service = \ImageOptimizer\Core\Container::get_priority_service();
$priority_service->detect_lcp_id();
// Apply cache headers for long-term caching
$header_manager = new \ImageOptimizer\Services\HeaderManager();
$header_manager->apply_cache_headers();
// Optimize critical rendering path
$asset_manager = \ImageOptimizer\Core\Container::get_asset_manager();
$asset_manager->optimize_critical_path();
}
}, 1);
/**
* Override WordPress font-display fallback at priority 0 (absolutely first in head)
* Must run before ALL other styles to ensure font-display: swap !important takes precedence
*
* Uses DI Container to manage PriorityService lifecycle.
*/
add_action('wp_head', function () {
if (! is_admin()) {
$priority_service = \ImageOptimizer\Core\Container::get_priority_service();
$priority_service->override_font_display();
}
}, 0);
/**
* Initialize frontend styles and fonts in wp_head (very early)
*
* Uses DI Container for PriorityService and AssetManager.
* Services are cached in Container singleton, ensuring consistent instance
* for state tracking (e.g., LCP ID detection -> preload injection).
*/
add_action('wp_head', function () {
if (! is_admin()) {
$priority_service = \ImageOptimizer\Core\Container::get_priority_service();
// Inject LCP preload hint (tell browser to download 704px image immediately)
$priority_service->inject_preload();
// Preload theme's primary font to reduce FCP variance
$priority_service->preload_theme_font();
// Inline small CSS to eliminate render-blocking request
$asset_manager = \ImageOptimizer\Core\Container::get_asset_manager();
$asset_manager->inline_frontend_styles();
// Preload critical fonts (breaks dependency chain)
// DEPRECATED: Now disabled, uses preload_theme_font() instead
$asset_manager->preload_critical_fonts();
}
}, 1);
// Initialize frontend WebP delivery for public-facing posts
add_action('wp', function () {
if (! is_admin()) {
\ImageOptimizer\Frontend\WebPFrontendDelivery::init();
// Create the delivery service for filter handling + connection hints
$delivery = new \ImageOptimizer\Frontend\FrontendDelivery();
// Add the strictly-typed Frontend_Delivery filter at priority 20
// This ensures we run after theme defaults but before other plugins
add_filter('wp_get_attachment_image_attributes', [ $delivery, 'serve_optimized_attributes' ], 20, 2);
// Add preconnect hints in wp_head (priority 1 = very early)
// Warms up DNS/SSL for media domain before browser reaches image tag
add_action('wp_head', [ $delivery, 'add_connection_hints' ], 1);
}
});
/**
* Defer navigation scripts to first user interaction (priority 998 = very late, after all plugins/themes enqueue)
*
* CRITICAL: Must run at priority 998 (just before CleanupService at 999)
* This ensures ALL scripts are registered before we dequeue/deregister navigation scripts.
* If we run too early, scripts enqueued later will override our dequeue.
*
* Uses DI Container to manage NavigationDeferralService lifecycle.
*/
add_action('wp_enqueue_scripts', function () {
if (! is_admin()) {
$deferral = \ImageOptimizer\Core\Container::get_navigation_deferral_service();
$deferral->defer_navigation();
}
}, 998);
/**
* Remove WordPress bloat (priority 999 = extremely late, after all plugins/themes enqueue)
*
* Uses DI Container to manage CleanupService lifecycle.
* Runs at maximum priority to ensure all scripts are enqueued before we dequeue.
* This prevents race conditions where scripts are enqueued after our dequeue.
*/
add_action('wp_enqueue_scripts', function () {
if (! is_admin()) {
$cleanup = \ImageOptimizer\Core\Container::get_cleanup_service();
$cleanup->remove_bloat();
}
}, 999);
/**
* Copyright (C) 2025 Danh Le
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA.
*/