PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 2.3.2
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v2.3.2
2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.9 2.2.8 trunk 1.10 1.3.3 1.3.4 1.3.5 1.3.5.1 1.3.5.2 1.3.6 1.3.6.1 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.5 All 103 releases
imagify / docs / imagify-summary.html

imagify-summary.html in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF 2.3.2, at docs/imagify-summary.html

1,011 lines 43.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 <title>Imagify — Complete Technical Summary</title>
7 <style>
8 :root {
9 --blue: #2B67F6;
10 --blue-l: #EBF0FE;
11 --green: #1DB954;
12 --green-l: #E6F8ED;
13 --orange: #F59E0B;
14 --orange-l:#FEF3C7;
15 --red: #EF4444;
16 --red-l: #FEE2E2;
17 --purple: #7C3AED;
18 --purple-l:#EDE9FE;
19 --gray: #6B7280;
20 --gray-l: #F3F4F6;
21 --dark: #111827;
22 --border: #E5E7EB;
23 --radius: 10px;
24 --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
25 --mono: "JetBrains Mono", "Fira Code", "Cascadia Code", monospace;
26 }
27
28 *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
29
30 body {
31 font-family: var(--font);
32 font-size: 15px;
33 line-height: 1.6;
34 color: var(--dark);
35 background: #F8FAFC;
36 }
37
38 /* ── HEADER ── */
39 header {
40 background: linear-gradient(135deg, #1a1f36 0%, #2B67F6 100%);
41 color: white;
42 padding: 48px 40px 40px;
43 text-align: center;
44 }
45 header .logo { font-size: 13px; letter-spacing: 3px; text-transform: uppercase; opacity: 0.6; margin-bottom: 12px; }
46 header h1 { font-size: 38px; font-weight: 800; margin-bottom: 10px; }
47 header p { font-size: 16px; opacity: 0.8; max-width: 620px; margin: 0 auto 20px; }
48 .version-badge {
49 display: inline-block;
50 background: rgba(255,255,255,0.15);
51 border: 1px solid rgba(255,255,255,0.25);
52 border-radius: 20px;
53 padding: 4px 16px;
54 font-size: 13px;
55 font-weight: 600;
56 }
57
58 /* ── LAYOUT ── */
59 .container { max-width: 1100px; margin: 0 auto; padding: 0 24px; }
60
61 /* ── TOC ── */
62 nav.toc {
63 background: white;
64 border: 1px solid var(--border);
65 border-radius: var(--radius);
66 padding: 28px 32px;
67 margin: 36px auto;
68 max-width: 1100px;
69 margin-left: 24px;
70 margin-right: 24px;
71 }
72 nav.toc h2 { font-size: 14px; font-weight: 700; text-transform: uppercase; letter-spacing: 1.5px; color: var(--gray); margin-bottom: 16px; }
73 nav.toc ol { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 6px 32px; padding-left: 20px; }
74 nav.toc li { font-size: 14px; }
75 nav.toc a { color: var(--blue); text-decoration: none; }
76 nav.toc a:hover { text-decoration: underline; }
77
78 /* ── SECTIONS ── */
79 section {
80 background: white;
81 border: 1px solid var(--border);
82 border-radius: var(--radius);
83 padding: 36px 40px;
84 margin: 20px 24px;
85 }
86 section + section { margin-top: 20px; }
87
88 .section-header {
89 display: flex;
90 align-items: flex-start;
91 gap: 18px;
92 margin-bottom: 28px;
93 padding-bottom: 20px;
94 border-bottom: 2px solid var(--border);
95 }
96 .section-icon {
97 width: 46px;
98 height: 46px;
99 border-radius: 10px;
100 display: flex;
101 align-items: center;
102 justify-content: center;
103 font-size: 22px;
104 flex-shrink: 0;
105 }
106 .section-header h2 { font-size: 22px; font-weight: 700; margin-bottom: 4px; }
107 .section-header p { font-size: 14px; color: var(--gray); }
108
109 /* colour presets for icons */
110 .ic-blue { background: var(--blue-l); }
111 .ic-green { background: var(--green-l); }
112 .ic-orange { background: var(--orange-l); }
113 .ic-red { background: var(--red-l); }
114 .ic-purple { background: var(--purple-l); }
115
116 /* ── SUBSECTIONS ── */
117 h3 {
118 font-size: 16px;
119 font-weight: 700;
120 color: var(--dark);
121 margin: 24px 0 12px;
122 display: flex;
123 align-items: center;
124 gap: 8px;
125 }
126 h3::before {
127 content: '';
128 display: inline-block;
129 width: 4px; height: 16px;
130 background: var(--blue);
131 border-radius: 2px;
132 }
133
134 /* ── PROSE ── */
135 p { margin-bottom: 12px; color: #374151; }
136 ul, ol { padding-left: 22px; margin-bottom: 12px; }
137 li { margin-bottom: 5px; color: #374151; }
138 li strong { color: var(--dark); }
139
140 /* ── PILL TAGS ── */
141 .tags { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 16px; }
142 .tag {
143 display: inline-flex; align-items: center; gap: 5px;
144 padding: 4px 12px;
145 border-radius: 20px;
146 font-size: 12px;
147 font-weight: 600;
148 }
149 .tag-blue { background: var(--blue-l); color: var(--blue); }
150 .tag-green { background: var(--green-l); color: #15803D; }
151 .tag-orange { background: var(--orange-l); color: #92400E; }
152 .tag-red { background: var(--red-l); color: var(--red); }
153 .tag-purple { background: var(--purple-l); color: var(--purple); }
154 .tag-gray { background: var(--gray-l); color: var(--gray); }
155
156 /* ── CODE ── */
157 code {
158 font-family: var(--mono);
159 font-size: 12.5px;
160 background: var(--gray-l);
161 border: 1px solid var(--border);
162 border-radius: 4px;
163 padding: 1px 6px;
164 color: #7C3AED;
165 }
166 pre {
167 font-family: var(--mono);
168 font-size: 12.5px;
169 background: #1E293B;
170 color: #E2E8F0;
171 border-radius: 8px;
172 padding: 20px 24px;
173 overflow-x: auto;
174 margin: 12px 0 20px;
175 line-height: 1.65;
176 }
177 pre .c { color: #64748B; } /* comment */
178 pre .k { color: #7DD3FC; } /* keyword / key */
179 pre .v { color: #86EFAC; } /* value */
180 pre .f { color: #FCA5A5; } /* function */
181 pre .s { color: #FCD34D; } /* string */
182
183 /* ── GRID CARDS ── */
184 .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin: 16px 0; }
185 .grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin: 16px 0; }
186 @media (max-width: 720px) {
187 .grid-2, .grid-3 { grid-template-columns: 1fr; }
188 }
189 .card {
190 border: 1px solid var(--border);
191 border-radius: 8px;
192 padding: 18px 20px;
193 background: #FAFAFA;
194 }
195 .card h4 { font-size: 14px; font-weight: 700; margin-bottom: 8px; color: var(--dark); }
196 .card p, .card li { font-size: 13px; color: var(--gray); }
197 .card ul { margin: 0; padding-left: 16px; }
198
199 /* ── TABLE ── */
200 table { width: 100%; border-collapse: collapse; font-size: 13.5px; margin: 16px 0 20px; }
201 th { background: var(--gray-l); text-align: left; padding: 10px 14px; font-weight: 700; font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--gray); border-bottom: 2px solid var(--border); }
202 td { padding: 10px 14px; border-bottom: 1px solid var(--border); vertical-align: top; }
203 tr:last-child td { border-bottom: none; }
204 tr:hover td { background: #F9FAFB; }
205
206 /* ── CALLOUT ── */
207 .callout {
208 display: flex; gap: 14px; align-items: flex-start;
209 padding: 16px 20px;
210 border-radius: 8px;
211 border-left: 4px solid;
212 margin: 16px 0;
213 font-size: 14px;
214 }
215 .callout-info { background: var(--blue-l); border-color: var(--blue); color: #1e3a8a; }
216 .callout-warning { background: var(--orange-l); border-color: var(--orange); color: #78350f; }
217 .callout-success { background: var(--green-l); border-color: var(--green); color: #14532d; }
218
219 /* ── FOOTER ── */
220 footer {
221 text-align: center;
222 padding: 40px;
223 font-size: 13px;
224 color: var(--gray);
225 margin-top: 20px;
226 }
227 </style>
228 </head>
229 <body>
230
231 <!-- ═══════════════════════════════════ HEADER ═══════════════════════════════════ -->
232 <header>
233 <div class="logo">Technical Documentation</div>
234 <h1>Imagify</h1>
235 <p>WordPress image optimisation plugin — compression, next-gen formats (WebP / AVIF), and multi-context management.</p>
236 <span class="version-badge">Version 2.2.8 · PHP 7.3+ · WordPress 5.3+</span>
237 </header>
238
239 <!-- ═══════════════════════════════════ TOC ═══════════════════════════════════ -->
240 <nav class="toc container">
241 <h2>Table of Contents</h2>
242 <ol>
243 <li><a href="#architecture">Architecture &amp; bootstrapping</a></li>
244 <li><a href="#optimisation">Image optimisation</a></li>
245 <li><a href="#nextgen">Next-gen formats (WebP / AVIF)</a></li>
246 <li><a href="#settings">Settings &amp; configuration</a></li>
247 <li><a href="#bulk">Bulk optimisation</a></li>
248 <li><a href="#media-library">WP Media Library integration</a></li>
249 <li><a href="#custom-folders">Custom folders</a></li>
250 <li><a href="#ajax-api">AJAX &amp; Admin-Post actions</a></li>
251 <li><a href="#cli">WP-CLI commands</a></li>
252 <li><a href="#ngg">NextGEN Gallery integration</a></li>
253 <li><a href="#third-party">Other third-party integrations</a></li>
254 <li><a href="#cron">Scheduled tasks (Cron)</a></li>
255 <li><a href="#hooks">Developer hooks &amp; filters</a></li>
256 <li><a href="#quota">Quota &amp; account management</a></li>
257 <li><a href="#roles">Roles &amp; access control</a></li>
258 <li><a href="#tools">Troubleshooting tools</a></li>
259 </ol>
260 </nav>
261
262 <!-- ═══════════════════════════════════ 1 — ARCHITECTURE ═══════════════════════════════════ -->
263 <section id="architecture">
264 <div class="section-header">
265 <div class="section-icon ic-blue">🏗️</div>
266 <div>
267 <h2>1. Architecture &amp; Bootstrapping</h2>
268 <p>Source code organisation, service loading, and plugin lifecycle.</p>
269 </div>
270 </div>
271
272 <h3>Entry point</h3>
273 <p>The plugin starts from <code>imagify.php</code>. It defines global constants, includes the Composer autoloader, then hooks the <code>imagify_init()</code> function on <code>plugins_loaded</code>.</p>
274
275 <div class="grid-2">
276 <div class="card">
277 <h4>Key constants</h4>
278 <ul>
279 <li><code>IMAGIFY_VERSION</code> — plugin version</li>
280 <li><code>IMAGIFY_PATH</code> / <code>IMAGIFY_URL</code></li>
281 <li><code>IMAGIFY_MAX_BYTES</code> — 5 MB limit per image</li>
282 <li><code>IMAGIFY_APP_API_URL</code> — remote API URL</li>
283 <li><code>IMAGIFY_API_KEY</code> — override via PHP constant</li>
284 </ul>
285 </div>
286 <div class="card">
287 <h4>Autoloading &amp; DI</h4>
288 <ul>
289 <li>PSR-4 via Composer (<code>vendor/autoload.php</code>)</li>
290 <li>Dependency injection: <strong>League Container</strong></li>
291 <li>Providers declared in <code>config/providers.php</code></li>
292 <li>Main class: <code>Imagify\Plugin</code></li>
293 <li>Final hook: <code>do_action('imagify_loaded')</code></li>
294 </ul>
295 </div>
296 </div>
297
298 <h3>Registered Service Providers</h3>
299 <div class="tags">
300 <span class="tag tag-blue">User</span>
301 <span class="tag tag-blue">Admin</span>
302 <span class="tag tag-blue">Avif</span>
303 <span class="tag tag-blue">CDN</span>
304 <span class="tag tag-blue">Picture</span>
305 <span class="tag tag-blue">Stats</span>
306 <span class="tag tag-blue">Webp</span>
307 <span class="tag tag-blue">ThirdParty</span>
308 <span class="tag tag-blue">Media</span>
309 <span class="tag tag-blue">Tools</span>
310 </div>
311
312 <h3>Initialisation sequence</h3>
313 <pre><span class="c">// 1. plugins_loaded</span>
314 imagify_init()
315 └── include vendor/autoload.php
316 └── new Imagify\Plugin()
317 └── load config/providers.php <span class="c">// register services</span>
318 └── boot Options, Data, Auth
319 └── boot Auto-Optimization
320 └── (admin only) boot Settings, Views, Imagifybeat
321 └── <span class="f">do_action</span>(<span class="s">'imagify_loaded'</span>)</pre>
322 </section>
323
324 <!-- ═══════════════════════════════════ 2 — OPTIMISATION ═══════════════════════════════════ -->
325 <section id="optimisation">
326 <div class="section-header">
327 <div class="section-icon ic-green"></div>
328 <div>
329 <h2>2. Image optimisation</h2>
330 <p>On-the-fly or bulk compression, quality levels, backup management, and resizing.</p>
331 </div>
332 </div>
333
334 <h3>Compression levels</h3>
335 <table>
336 <thead>
337 <tr><th>Level</th><th>Name</th><th>Description</th></tr>
338 </thead>
339 <tbody>
340 <tr><td><code>0</code></td><td>Normal</td><td>Light compression, maximum quality preserved.</td></tr>
341 <tr><td><code>1</code></td><td>Aggressive</td><td>Stronger compression, good quality/size trade-off.</td></tr>
342 <tr><td><code>2</code></td><td>Ultra (default)</td><td>Maximum compression — recommended for most use cases.</td></tr>
343 </tbody>
344 </table>
345
346 <div class="callout callout-info">
347 All optimisation operations go through the <code>Imagify\Optimization\File</code> class, which communicates with the remote Imagify API.
348 </div>
349
350 <h3>Automatic optimisation on upload</h3>
351 <p>When the <code>auto_optimize</code> option is enabled, the <code>Imagify_Auto_Optimization</code> class hooks into <code>wp_generate_attachment_metadata</code>. Each uploaded image is optimised immediately, along with all its thumbnails.</p>
352
353 <h3>Backup system</h3>
354 <ul>
355 <li>Enabled via the <code>backup</code> option.</li>
356 <li>The original file is copied before any compression.</li>
357 <li>Backup directory is filterable via <code>imagify_backup_directory</code>.</li>
358 <li>Restoring puts the original back in place and removes optimisation metadata.</li>
359 </ul>
360
361 <h3>Large image resizing</h3>
362 <ul>
363 <li>Option <code>resize_larger</code>: when enabled, images exceeding <code>resize_larger_w</code> pixels wide are resized.</li>
364 <li>Default value: <strong>2560 px</strong> (aligned with the WP filter <code>big_image_size_threshold</code>).</li>
365 </ul>
366
367 <h3>Thumbnail management</h3>
368 <p>All sizes registered in WordPress are optimised. Sizes can be excluded via the <code>disallowed-sizes</code> blacklist in the settings.</p>
369
370 <h3>Optimisation statuses</h3>
371 <div class="tags">
372 <span class="tag tag-green">success</span>
373 <span class="tag tag-gray">already_optimized</span>
374 <span class="tag tag-red">error</span>
375 <span class="tag tag-orange">pending</span>
376 </div>
377
378 <h3>Metadata stored per attachment</h3>
379 <pre><span class="c">// Attachment post meta</span>
380 _imagify_status <span class="c">// 'success' | 'already_optimized' | 'error' | 'pending'</span>
381 _imagify_data <span class="c">// JSON — full optimisation results</span>
382 _imagify_level <span class="c">// Level used (0, 1, 2)</span>
383 _imagify_next_gen_done <span class="c">// Boolean — next-gen versions generated</span></pre>
384 </section>
385
386 <!-- ═══════════════════════════════════ 3 — NEXT-GEN ═══════════════════════════════════ -->
387 <section id="nextgen">
388 <div class="section-header">
389 <div class="section-icon ic-purple">🖼️</div>
390 <div>
391 <h2>3. Next-gen formats (WebP / AVIF)</h2>
392 <p>Generation and delivery of modern formats to reduce image weight on the browser side.</p>
393 </div>
394 </div>
395
396 <h3>File generation</h3>
397 <p>After optimisation, Imagify can generate <strong>WebP</strong> and/or <strong>AVIF</strong> versions of each image. The <code>optimization_format</code> option controls this behaviour:</p>
398 <table>
399 <thead>
400 <tr><th>Value</th><th>Behaviour</th></tr>
401 </thead>
402 <tbody>
403 <tr><td><code>'off'</code></td><td>No next-gen format.</td></tr>
404 <tr><td><code>'webp'</code></td><td>Generates WebP only.</td></tr>
405 <tr><td><code>'avif'</code></td><td>Generates WebP + AVIF (AVIF takes priority if supported).</td></tr>
406 </tbody>
407 </table>
408
409 <h3>Display method: &lt;picture&gt;</h3>
410 <p>Class: <code>Imagify\Picture\Display</code>. The plugin starts an output buffer on <code>template_redirect</code>, scans the generated HTML, and replaces each <code>&lt;img&gt;</code> with a <code>&lt;picture&gt;</code> block containing <code>&lt;source&gt;</code> elements pointing to the WebP/AVIF files.</p>
411 <pre><span class="c">&lt;!-- Before --&gt;</span>
412 &lt;img src="photo.jpg" alt="..."&gt;
413
414 <span class="c">&lt;!-- After transformation --&gt;</span>
415 &lt;picture&gt;
416 &lt;source srcset="photo.avif" type="image/avif"&gt;
417 &lt;source srcset="photo.webp" type="image/webp"&gt;
418 &lt;img src="photo.jpg" alt="..."&gt;
419 &lt;/picture&gt;</pre>
420
421 <h3>Display method: Server rewrite</h3>
422 <p>Class: <code>Imagify\Webp\Display</code>. Rather than altering the HTML, rules are written directly into <code>.htaccess</code> (Apache) or <code>web.config</code> (IIS). The server automatically serves WebP if the browser accepts it (<code>Accept: image/webp</code>).</p>
423
424 <div class="grid-2">
425 <div class="card">
426 <h4>Lazy Load compatibility</h4>
427 <p>The <code>data-lazy-src</code>, <code>data-src</code>, <code>data-srcset</code>, <code>data-lazy-srcset</code> attributes are detected and propagated into the generated <code>&lt;source&gt;</code> and <code>&lt;img&gt;</code> tags.</p>
428 </div>
429 <div class="card">
430 <h4>Image exclusion</h4>
431 <p>An image with the CSS class <code>imagify-no-webp</code> is ignored by the <code>&lt;picture&gt;</code> transformation.</p>
432 </div>
433 </div>
434
435 <div class="callout callout-warning">
436 <strong>Warning:</strong> the server rewrite method requires the web server to be Apache or IIS and that the configuration files (.htaccess) be writable.
437 </div>
438 </section>
439
440 <!-- ═══════════════════════════════════ 4 — SETTINGS ═══════════════════════════════════ -->
441 <section id="settings">
442 <div class="section-header">
443 <div class="section-icon ic-orange">⚙️</div>
444 <div>
445 <h2>4. Settings &amp; configuration</h2>
446 <p>All options stored in <code>imagify_settings</code> (wp_options / wp_sitemeta on multisite).</p>
447 </div>
448 </div>
449
450 <table>
451 <thead>
452 <tr><th>Key</th><th>Type</th><th>Default</th><th>Description</th></tr>
453 </thead>
454 <tbody>
455 <tr><td><code>api_key</code></td><td>string</td><td><code>''</code></td><td>Imagify API key (or the <code>IMAGIFY_API_KEY</code> constant).</td></tr>
456 <tr><td><code>optimization_level</code></td><td>int</td><td><code>2</code></td><td>Compression level (0, 1, 2).</td></tr>
457 <tr><td><code>lossless</code></td><td>bool</td><td><code>0</code></td><td>Lossless compression.</td></tr>
458 <tr><td><code>auto_optimize</code></td><td>bool</td><td><code>1</code></td><td>Automatic optimisation on upload.</td></tr>
459 <tr><td><code>backup</code></td><td>bool</td><td><code>1</code></td><td>Back up the original before compression.</td></tr>
460 <tr><td><code>resize_larger</code></td><td>bool</td><td><code>0</code></td><td>Resize images that are too large.</td></tr>
461 <tr><td><code>resize_larger_w</code></td><td>int</td><td><code>0</code></td><td>Maximum width in pixels.</td></tr>
462 <tr><td><code>optimization_format</code></td><td>string</td><td><code>'webp'</code></td><td><code>'off'</code>, <code>'webp'</code>, or <code>'avif'</code>.</td></tr>
463 <tr><td><code>display_nextgen_method</code></td><td>string</td><td><code>'picture'</code></td><td><code>'picture'</code> or <code>'rewrite'</code>.</td></tr>
464 <tr><td><code>cdn_url</code></td><td>string</td><td><code>''</code></td><td>CDN URL for serving media.</td></tr>
465 <tr><td><code>disallowed-sizes</code></td><td>array</td><td><code>[]</code></td><td>Thumbnail sizes excluded from optimisation.</td></tr>
466 <tr><td><code>admin_bar_menu</code></td><td>bool</td><td><code>1</code></td><td>Show Imagify in the admin bar.</td></tr>
467 </tbody>
468 </table>
469
470 <div class="callout callout-info">
471 The <code>Imagify_Settings</code> class handles option registration (<code>register_setting()</code>) and validation. It is network-aware: on multisite, network options are stored in <code>wp_sitemeta</code>.
472 </div>
473 </section>
474
475 <!-- ═══════════════════════════════════ 5 — BULK ═══════════════════════════════════ -->
476 <section id="bulk">
477 <div class="section-header">
478 <div class="section-icon ic-green">🚀</div>
479 <div>
480 <h2>5. Bulk optimisation</h2>
481 <p>Batch processing of all existing images, with an asynchronous queue.</p>
482 </div>
483 </div>
484
485 <h3>Bulk architecture</h3>
486 <p>The <code>Imagify\Bulk\Bulk</code> class orchestrates bulk optimisation. It relies on <strong>ActionScheduler</strong> (bundled library) to create asynchronous jobs processed in the background.</p>
487
488 <div class="grid-3">
489 <div class="card">
490 <h4>WP Media context</h4>
491 <p>Class: <code>Imagify\Bulk\WP</code></p>
492 <p>Optimises all attachments in the WordPress media library that have not yet been optimised.</p>
493 </div>
494 <div class="card">
495 <h4>Custom Folders context</h4>
496 <p>Class: <code>Imagify\Bulk\CustomFolders</code></p>
497 <p>Optimises files indexed in the custom folders.</p>
498 </div>
499 <div class="card">
500 <h4>NGG context</h4>
501 <p>Class: <code>Imagify\Bulk\NGG</code></p>
502 <p>Optimises images from NextGEN Gallery galleries.</p>
503 </div>
504 </div>
505
506 <h3>Execution flow</h3>
507 <pre><span class="c">// Trigger (UI or CLI)</span>
508 imagify_bulk_optimize (AJAX) <span class="c">// or wp imagify bulk-optimize</span>
509 └── Imagify\Bulk\Bulk::run()
510 └── ActionScheduler::enqueue(imagify_optimize_media)
511 └── Imagify\Job\MediaOptimization::execute()
512 └── Imagify\Optimization\File::optimize()
513 └── Remote Imagify API</pre>
514
515 <h3>Bulk next-gen version generation</h3>
516 <p>The AJAX action <code>imagify_missing_nextgen_generation</code> and the ActionScheduler hook <code>imagify_convert_next_gen</code> allow generating WebP/AVIF versions for all already-optimised images whose next-gen files are missing.</p>
517 </section>
518
519 <!-- ═══════════════════════════════════ 6 — MEDIA LIBRARY ═══════════════════════════════════ -->
520 <section id="media-library">
521 <div class="section-header">
522 <div class="section-icon ic-blue">📁</div>
523 <div>
524 <h2>6. WordPress Media Library integration</h2>
525 <p>Columns, actions, and buttons directly within the WordPress media interface.</p>
526 </div>
527 </div>
528
529 <div class="grid-2">
530 <div class="card">
531 <h4>List view (Media Library)</h4>
532 <ul>
533 <li>"Imagify" column with status and weight savings.</li>
534 <li>Inline action buttons: Optimize, Re-optimize, Restore, Generate next-gen, Delete next-gen.</li>
535 <li>"Bulk Optimization" group action.</li>
536 <li>Filter by status: <code>?imagify-status=...</code>.</li>
537 </ul>
538 </div>
539 <div class="card">
540 <h4>Attachment edit page</h4>
541 <ul>
542 <li>Dedicated metabox with detailed status.</li>
543 <li>Individual optimisation buttons.</li>
544 <li>Display of savings achieved (KB and %).</li>
545 <li>Restore link to the original.</li>
546 </ul>
547 </div>
548 </div>
549
550 <div class="callout callout-info">
551 The WordPress admin bar can also display a shortcut to the Bulk Optimization page, controlled by the <code>admin_bar_menu</code> option.
552 </div>
553 </section>
554
555 <!-- ═══════════════════════════════════ 7 — CUSTOM FOLDERS ═══════════════════════════════════ -->
556 <section id="custom-folders">
557 <div class="section-header">
558 <div class="section-icon ic-orange">📂</div>
559 <div>
560 <h2>7. Custom Folders</h2>
561 <p>Optimisation of image files located outside the WordPress media library.</p>
562 </div>
563 </div>
564
565 <h3>Principle</h3>
566 <p>Custom folders allow optimising images located anywhere on the server (themes, plugins, custom directories). They are indexed in two dedicated MySQL tables.</p>
567
568 <div class="grid-2">
569 <div class="card">
570 <h4>Table <code>imagify_folders</code></h4>
571 <ul>
572 <li>Monitored directories</li>
573 <li>Absolute path on the server</li>
574 <li>Scan status</li>
575 </ul>
576 </div>
577 <div class="card">
578 <h4>Table <code>imagify_files</code></h4>
579 <ul>
580 <li>Individually indexed files</li>
581 <li>Original / optimised size</li>
582 <li>Status, level, generated formats</li>
583 <li>Hash to detect modifications</li>
584 </ul>
585 </div>
586 </div>
587
588 <h3>Available features</h3>
589 <ul>
590 <li><strong>Scan</strong>: automatic detection of new images in configured folders.</li>
591 <li><strong>Individual or bulk optimisation</strong> via the same ActionScheduler system.</li>
592 <li><strong>Re-optimisation</strong>: if the source file has been modified (detected by hash).</li>
593 <li><strong>Restore</strong> from backup.</li>
594 <li><strong>Cron synchronisation</strong> to detect modified/deleted files.</li>
595 </ul>
596
597 <h3>Main classes</h3>
598 <pre><span class="c">// Database access</span>
599 Imagify_Files_DB <span class="c">// CRUD on wp_imagify_files</span>
600 Imagify_Folders_DB <span class="c">// CRUD on wp_imagify_folders</span>
601 Imagify_Files_Scan <span class="c">// Filesystem scan</span>
602
603 <span class="c">// Context</span>
604 Imagify\Context\CustomFolders</pre>
605 </section>
606
607 <!-- ═══════════════════════════════════ 8 — AJAX API ═══════════════════════════════════ -->
608 <section id="ajax-api">
609 <div class="section-header">
610 <div class="section-icon ic-purple">🔌</div>
611 <div>
612 <h2>8. AJAX &amp; Admin-Post actions</h2>
613 <p>All server entry points used by the administration interface.</p>
614 </div>
615 </div>
616
617 <div class="callout callout-info">
618 The plugin does not expose a standard WordPress REST API. All actions go through <code>wp_ajax_*</code> (authenticated) or <code>admin_post_*</code>. A custom "Imagifybeat" system handles real-time updates.
619 </div>
620
621 <h3>AJAX actions (<code>wp_ajax_*</code>)</h3>
622 <div class="grid-2">
623 <div class="card">
624 <h4>Account &amp; API</h4>
625 <ul>
626 <li><code>imagify_signup</code></li>
627 <li><code>imagify_check_api_key_validity</code></li>
628 <li><code>imagify_get_user_data</code></li>
629 <li><code>imagify_delete_user_data_cache</code></li>
630 <li><code>imagify_get_prices</code></li>
631 <li><code>imagify_check_coupon</code></li>
632 </ul>
633 </div>
634 <div class="card">
635 <h4>Bulk &amp; stats</h4>
636 <ul>
637 <li><code>imagify_bulk_optimize</code></li>
638 <li><code>imagify_missing_nextgen_generation</code></li>
639 <li><code>imagify_bulk_get_stats</code></li>
640 <li><code>imagify_get_folder_type_data</code></li>
641 <li><code>imagify_bulk_info_seen</code></li>
642 <li><code>imagify_get_images_counts</code></li>
643 </ul>
644 </div>
645 <div class="card">
646 <h4>UI &amp; settings</h4>
647 <ul>
648 <li><code>imagify_check_backup_dir_is_writable</code></li>
649 <li><code>imagify_get_files_tree</code></li>
650 <li><code>imagify_update_estimate_sizes</code></li>
651 </ul>
652 </div>
653 <div class="card">
654 <h4>Tools</h4>
655 <ul>
656 <li><code>imagify_reset_internal_state</code></li>
657 <li><code>imagify_rpc</code> (Imagifybeat)</li>
658 </ul>
659 </div>
660 </div>
661
662 <h3>Admin-Post actions (<code>admin_post_*</code>)</h3>
663 <div class="grid-2">
664 <div class="card">
665 <h4>WP Media Library</h4>
666 <ul>
667 <li><code>imagify_manual_optimize</code></li>
668 <li><code>imagify_manual_reoptimize</code></li>
669 <li><code>imagify_optimize_missing_sizes</code></li>
670 <li><code>imagify_generate_nextgen_versions</code></li>
671 <li><code>imagify_delete_nextgen_versions</code></li>
672 <li><code>imagify_restore</code></li>
673 </ul>
674 </div>
675 <div class="card">
676 <h4>Custom folders</h4>
677 <ul>
678 <li><code>imagify_optimize_file</code></li>
679 <li><code>imagify_reoptimize_file</code></li>
680 <li><code>imagify_restore_file</code></li>
681 <li><code>imagify_refresh_file_modified</code></li>
682 <li><code>imagify_scan_custom_folders</code></li>
683 </ul>
684 </div>
685 </div>
686
687 <h3>Imagifybeat</h3>
688 <p>Real-time update system (analogous to WordPress Heartbeat). Hook: <code>wp_ajax_imagifybeat</code>. Interface data (nonces, statuses) is refreshed periodically via AJAX polling, configurable by filter.</p>
689 </section>
690
691 <!-- ═══════════════════════════════════ 9 — CLI ═══════════════════════════════════ -->
692 <section id="cli">
693 <div class="section-header">
694 <div class="section-icon ic-blue">💻</div>
695 <div>
696 <h2>9. WP-CLI commands</h2>
697 <p>Command-line interface for automating optimisation operations.</p>
698 </div>
699 </div>
700
701 <div class="grid-3">
702 <div class="card">
703 <h4><code>wp imagify bulk-optimize</code></h4>
704 <p>Launches bulk optimisation for one or more contexts (<code>wp</code>, <code>custom-folders</code>).</p>
705 <ul>
706 <li>Option: <code>--optimization-level</code></li>
707 <li>Asynchronous execution via ActionScheduler</li>
708 </ul>
709 </div>
710 <div class="card">
711 <h4><code>wp imagify restore</code></h4>
712 <p>Restores original images for the specified contexts (<code>library</code>, <code>custom-folders</code>).</p>
713 <ul>
714 <li>Synchronous (blocking) execution</li>
715 <li>Returns: success, errors, total</li>
716 </ul>
717 </div>
718 <div class="card">
719 <h4><code>wp imagify generate-missing-nextgen</code></h4>
720 <p>Generates missing WebP/AVIF versions for all already-optimised images.</p>
721 <ul>
722 <li>Useful after enabling a next-gen format</li>
723 </ul>
724 </div>
725 </div>
726 </section>
727
728 <!-- ═══════════════════════════════════ 10 — NGG ═══════════════════════════════════ -->
729 <section id="ngg">
730 <div class="section-header">
731 <div class="section-icon ic-green">🖼️</div>
732 <div>
733 <h2>10. NextGEN Gallery integration</h2>
734 <p>Full support for the NextGEN Gallery (NGG) plugin.</p>
735 </div>
736 </div>
737
738 <p>The plugin automatically detects NextGEN Gallery and activates a dedicated context (<code>Imagify\Context\NGG</code>).</p>
739
740 <div class="grid-2">
741 <div class="card">
742 <h4>Features</h4>
743 <ul>
744 <li>Optimisation of NGG images (levels 0/1/2)</li>
745 <li>WebP / AVIF generation for NGG images</li>
746 <li>Restore NGG originals</li>
747 <li>Backup before compression</li>
748 </ul>
749 </div>
750 <div class="card">
751 <h4>Interface</h4>
752 <ul>
753 <li>"Bulk Optimization" page in the NGG menu</li>
754 <li>"Imagify" column in "Manage Images"</li>
755 <li>Verified compatibility: NGG v4.x (<code>imagify_ngg_has_pope_storage()</code>)</li>
756 </ul>
757 </div>
758 </div>
759 </section>
760
761 <!-- ═══════════════════════════════════ 11 — THIRD PARTY ═══════════════════════════════════ -->
762 <section id="third-party">
763 <div class="section-header">
764 <div class="section-icon ic-orange">🔗</div>
765 <div>
766 <h2>11. Third-party integrations</h2>
767 <p>Compatibility with other plugins and WordPress hosts.</p>
768 </div>
769 </div>
770
771 <h3>Plugins</h3>
772 <div class="tags">
773 <span class="tag tag-blue">WooCommerce</span>
774 <span class="tag tag-blue">WP Rocket</span>
775 <span class="tag tag-blue">Gravity Forms</span>
776 <span class="tag tag-blue">Formidable Pro</span>
777 <span class="tag tag-blue">Yoast SEO</span>
778 <span class="tag tag-blue">AMP</span>
779 <span class="tag tag-blue">Enable Media Replace</span>
780 <span class="tag tag-blue">Regenerate Thumbnails</span>
781 <span class="tag tag-blue">Amazon S3 &amp; CloudFront</span>
782 <span class="tag tag-blue">Real Media Library</span>
783 <span class="tag tag-blue">Extendify</span>
784 <span class="tag tag-blue">Cloudflare Super Page Cache</span>
785 </div>
786
787 <h3>WooCommerce detail</h3>
788 <p>On variable product pages, WooCommerce dynamically replaces the main image. Imagify fixes the <code>wp-post-image</code> class on generated <code>&lt;picture&gt;</code> tags to maintain compatibility with WooCommerce's image-switching mechanism.</p>
789
790 <h3>Hosts</h3>
791 <div class="tags">
792 <span class="tag tag-gray">WordPress.com</span>
793 <span class="tag tag-gray">WP Engine</span>
794 <span class="tag tag-gray">Flywheel</span>
795 <span class="tag tag-gray">SiteGround</span>
796 <span class="tag tag-gray">Pressable</span>
797 </div>
798 </section>
799
800 <!-- ═══════════════════════════════════ 12 — CRON ═══════════════════════════════════ -->
801 <section id="cron">
802 <div class="section-header">
803 <div class="section-icon ic-purple">🕐</div>
804 <div>
805 <h2>12. Scheduled tasks (Cron)</h2>
806 <p>Recurring jobs for maintenance and statistics.</p>
807 </div>
808 </div>
809
810 <table>
811 <thead>
812 <tr><th>Task</th><th>WP Cron hook</th><th>Frequency</th><th>Role</th></tr>
813 </thead>
814 <tbody>
815 <tr>
816 <td><code>Imagify_Cron_Rating</code></td>
817 <td><code>imagify_rating_event</code></td>
818 <td>Daily (3:00 PM)</td>
819 <td>Triggers the plugin rating request.</td>
820 </tr>
821 <tr>
822 <td><code>Imagify_Cron_Library_Size</code></td>
823 <td></td>
824 <td>Periodic</td>
825 <td>Recalculates media library statistics.</td>
826 </tr>
827 <tr>
828 <td><code>Imagify_Cron_Sync_Files</code></td>
829 <td></td>
830 <td>Periodic</td>
831 <td>Synchronises files in custom folders.</td>
832 </tr>
833 </tbody>
834 </table>
835
836 <h3>ActionScheduler</h3>
837 <p>The ActionScheduler library is bundled in <code>/inc/Dependencies/ActionScheduler/</code>. It manages asynchronous optimisation jobs:</p>
838 <ul>
839 <li><code>imagify_optimize_media</code> — Processes a single optimisation job.</li>
840 <li><code>imagify_convert_next_gen</code> — Generates next-gen versions.</li>
841 </ul>
842 <p>All jobs are cleaned up when the plugin is deactivated.</p>
843 </section>
844
845 <!-- ═══════════════════════════════════ 13 — HOOKS ═══════════════════════════════════ -->
846 <section id="hooks">
847 <div class="section-header">
848 <div class="section-icon ic-blue">🪝</div>
849 <div>
850 <h2>13. Developer hooks &amp; filters</h2>
851 <p>Extension points for customising the plugin's behaviour.</p>
852 </div>
853 </div>
854
855 <h3>Main actions</h3>
856 <table>
857 <thead>
858 <tr><th>Hook</th><th>When</th></tr>
859 </thead>
860 <tbody>
861 <tr><td><code>imagify_loaded</code></td><td>Plugin fully loaded and ready.</td></tr>
862 <tr><td><code>imagify_activation</code></td><td>On plugin activation.</td></tr>
863 <tr><td><code>imagify_deactivation</code></td><td>On plugin deactivation.</td></tr>
864 <tr><td><code>imagify_optimize_media</code></td><td>ActionScheduler optimisation job.</td></tr>
865 <tr><td><code>imagify_convert_next_gen</code></td><td>Next-gen generation job.</td></tr>
866 <tr><td><code>imagify_delete_media</code></td><td>Deletion of a media item.</td></tr>
867 <tr><td><code>imagify_settings_on_save</code></td><td>After settings are saved.</td></tr>
868 <tr><td><code>imagify_not_over_quota_anymore</code></td><td>Quota dropped back below 100%.</td></tr>
869 </tbody>
870 </table>
871
872 <h3>Main filters</h3>
873 <table>
874 <thead>
875 <tr><th>Filter</th><th>Usage</th></tr>
876 </thead>
877 <tbody>
878 <tr><td><code>imagify_backup_directory</code></td><td>Change the backup folder.</td></tr>
879 <tr><td><code>imagify_register_context</code></td><td>Register a custom optimisation context.</td></tr>
880 <tr><td><code>imagify_picture_attributes</code></td><td>Modify attributes of the <code>&lt;picture&gt;</code> tag.</td></tr>
881 <tr><td><code>imagify_picture_source_attributes</code></td><td>Modify attributes of <code>&lt;source&gt;</code> tags.</td></tr>
882 <tr><td><code>imagify_picture_img_attributes</code></td><td>Modify attributes of the inner <code>&lt;img&gt;</code>.</td></tr>
883 <tr><td><code>imagify_allow_picture_tags_for_nextgen</code></td><td>Disable the <code>&lt;picture&gt;</code> transformation.</td></tr>
884 <tr><td><code>imagify_buffer</code></td><td>Filter the final HTML page buffer.</td></tr>
885 <tr><td><code>imagify_cdn_source_url</code></td><td>Override the CDN URL.</td></tr>
886 <tr><td><code>imagify_event_recurrence</code></td><td>Change the frequency of Imagify cron jobs.</td></tr>
887 <tr><td><code>imagify_event_time</code></td><td>Change the trigger time for cron jobs.</td></tr>
888 <tr><td><code>imagify_bulk_stats</code></td><td>Modify bulk statistics data.</td></tr>
889 <tr><td><code>imagify_unoptimized_attachment_limit</code></td><td>Limit query results.</td></tr>
890 </tbody>
891 </table>
892 </section>
893
894 <!-- ═══════════════════════════════════ 14 — QUOTA ═══════════════════════════════════ -->
895 <section id="quota">
896 <div class="section-header">
897 <div class="section-icon ic-orange">📊</div>
898 <div>
899 <h2>14. Quota &amp; account management</h2>
900 <p>Subscription plans, quota consumption, and user data cache.</p>
901 </div>
902 </div>
903
904 <h3>Available plans</h3>
905 <div class="grid-3">
906 <div class="card">
907 <h4>Free</h4>
908 <p><code>plan_id = 1</code></p>
909 <p>Limited monthly quota. Blocked at 100% consumption (<code>is_over_quota()</code>).</p>
910 </div>
911 <div class="card">
912 <h4>Growth</h4>
913 <p><code>plan_id = 16 / 18</code></p>
914 <p>Larger monthly quota, additional byte packs available.</p>
915 </div>
916 <div class="card">
917 <h4>Infinite</h4>
918 <p><code>plan_id = 15 / 17</code></p>
919 <p>Unlimited quota — no quota blocking.</p>
920 </div>
921 </div>
922
923 <h3>Data exposed by <code>Imagify\User\User</code></h3>
924 <pre><span class="k">quota</span> <span class="c">// Total monthly quota (MB)</span>
925 <span class="k">consumed_current_month_quota</span> <span class="c">// Quota consumed this month (MB)</span>
926 <span class="k">extra_quota</span> <span class="c">// Imagify byte pack (MB)</span>
927 <span class="k">extra_quota_consumed</span> <span class="c">// Pack consumed (MB)</span>
928 <span class="k">next_date_update</span> <span class="c">// Quota reset date</span>
929 <span class="k">is_active</span> <span class="c">// Account active</span></pre>
930
931 <h3>Cache</h3>
932 <p>User data is cached in a WordPress transient (<code>imagify_user_cache</code>) for <strong>5 minutes</strong>. The cache can be manually cleared via the AJAX action <code>imagify_delete_user_data_cache</code>.</p>
933 </section>
934
935 <!-- ═══════════════════════════════════ 15 — ROLES ═══════════════════════════════════ -->
936 <section id="roles">
937 <div class="section-header">
938 <div class="section-icon ic-red">🔐</div>
939 <div>
940 <h2>15. Roles &amp; access control</h2>
941 <p>WordPress capabilities required for each Imagify action.</p>
942 </div>
943 </div>
944
945 <table>
946 <thead>
947 <tr><th>Action</th><th>Required WP capability</th><th>Context</th></tr>
948 </thead>
949 <tbody>
950 <tr><td><code>manage</code> — Access settings</td><td><code>manage_options</code></td><td>All</td></tr>
951 <tr><td><code>optimize</code> — Optimize a media item</td><td><code>upload_files</code></td><td>All</td></tr>
952 <tr><td><code>bulk-optimize</code> — Launch a bulk run</td><td><code>manage_options</code></td><td>All</td></tr>
953 </tbody>
954 </table>
955
956 <div class="callout callout-info">
957 Capabilities are defined in <code>Imagify\Context\AbstractContext::get_capacity()</code> and can be overridden via the standard WordPress filter <code>option_page_capability_imagify</code>.
958 </div>
959 </section>
960
961 <!-- ═══════════════════════════════════ 16 — TOOLS ═══════════════════════════════════ -->
962 <section id="tools">
963 <div class="section-header">
964 <div class="section-icon ic-red">🔧</div>
965 <div>
966 <h2>16. Troubleshooting tools</h2>
967 <p>Built-in tools to resolve common issues without technical intervention.</p>
968 </div>
969 </div>
970
971 <h3>Internal state reset</h3>
972 <p>AJAX action: <code>imagify_reset_internal_state</code> (requires the <code>manage</code> capability). This one-click tool unblocks the bulk optimiser when it gets stuck in an inconsistent state.</p>
973
974 <h3>What gets cleaned up</h3>
975 <div class="grid-2">
976 <div class="card">
977 <h4>Deleted transients</h4>
978 <ul>
979 <li><code>imagify_custom-folders_optimize_running</code></li>
980 <li><code>imagify_wp_optimize_running</code></li>
981 <li><code>imagify_bulk_optimization_complete</code></li>
982 <li><code>imagify_bulk_optimization_result</code></li>
983 <li><code>imagify_missing_next_gen_total</code></li>
984 <li><code>imagify_bulk_optimization_infos</code></li>
985 </ul>
986 </div>
987 <div class="card">
988 <h4>Deleted locks &amp; jobs</h4>
989 <ul>
990 <li>Auto-optimize locks (<code>_transient_%imagify-auto-optimize-%</code>)</li>
991 <li>RPC locks (<code>_transient_%imagify_rpc_%</code>)</li>
992 <li>Process locks (<code>_transient_imagify_%_process_locked</code>)</li>
993 <li>ActionScheduler jobs: <code>imagify_optimize_media</code></li>
994 <li>ActionScheduler jobs: <code>imagify_convert_next_gen</code></li>
995 </ul>
996 </div>
997 </div>
998
999 <div class="callout callout-success">
1000 The <code>Imagify\Tools\InternalStateList</code> class is the single source of truth for all these items — it is also used by <code>uninstall.php</code> for a full cleanup on uninstallation.
1001 </div>
1002 </section>
1003
1004 <!-- ═══════════════════════════════════ FOOTER ═══════════════════════════════════ -->
1005 <footer>
1006 Imagify v2.2.8 · wp-media/imagify-plugin · Summary generated on 17 June 2026
1007 </footer>
1008
1009 </body>
1010 </html>
1011