| 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 & 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 & 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 & 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 & filters</a></li> |
| 256 |
<li><a href="#quota">Quota & account management</a></li> |
| 257 |
<li><a href="#roles">Roles & 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 & 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 & 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: <picture></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><img></code> with a <code><picture></code> block containing <code><source></code> elements pointing to the WebP/AVIF files.</p> |
| 411 |
<pre><span class="c"><!-- Before --></span> |
| 412 |
<img src="photo.jpg" alt="..."> |
| 413 |
|
| 414 |
<span class="c"><!-- After transformation --></span> |
| 415 |
<picture> |
| 416 |
<source srcset="photo.avif" type="image/avif"> |
| 417 |
<source srcset="photo.webp" type="image/webp"> |
| 418 |
<img src="photo.jpg" alt="..."> |
| 419 |
</picture></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><source></code> and <code><img></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><picture></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 & 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 & 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 & 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 & 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 & 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 & 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><picture></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 & 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><picture></code> tag.</td></tr> |
| 881 |
<tr><td><code>imagify_picture_source_attributes</code></td><td>Modify attributes of <code><source></code> tags.</td></tr> |
| 882 |
<tr><td><code>imagify_picture_img_attributes</code></td><td>Modify attributes of the inner <code><img></code>.</td></tr> |
| 883 |
<tr><td><code>imagify_allow_picture_tags_for_nextgen</code></td><td>Disable the <code><picture></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 & 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 & 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 & 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 |
|