Developer notes
How copies are stored and served
Section titled “How copies are stored and served”- Sources are the files of the CS-Cart images storage, addressed by their path inside it:
detailed/1/shoe.jpg,thumbnails/280/280/detailed/1/shoe.jpg,promo/2/banner.png. - Copies are separate files in the same storage:
images/kv_image_optimizer_webp/<path>.webpand<path>.avif. Originals and core thumbnails are never renamed or replaced; the core thumbnail names (thumbnails/<w>/<h>/<path>[.webp]) stay the core’s. - Serving: the PHP hook
smarty_block_hook_postrewrites the output of the template hookcommon:image(corecommon/image.tpl, used by Responsive, Bright, Nova and the banners, product lists, product pages, scrollers and quick view). For each<img class="… cm-image">it mapssrc/srcset(anddata-src/data-srcsetof carousels) to the source files and adds a<source>per format when every candidate has a copy that exists and is newer than its source (filemtime). No database query; two or threestatcalls per image. - Freshness: a copy older than its source is never served, so an image replaced in the admin panel, by import or by FTP shows the new original until the next run made new copies. The hooks
update_imageanddelete_imagealso delete the copies of a replaced or deleted image (and of its thumbnails) at once. - Full page cache (4.21): the markup depends only on files, settings and the licence state, never on the visitor (no
Acceptheader negotiation, cookies or session), so a cached page is right for every guest. Storefront requests write nothing to the database or?:storage_data; the only storefront write is one line appended tovar/kv_image_optimizer_webp/new.txtwhen the core generates a new thumbnail (a hint for the next run). - Block cache:
schemas/block_manager/block_cache_properties.post.phpadds the callable handlerkv_iow(fn_kv_image_optimizer_webp_cache_key(): licence state, delivery and lazy-loading settings, a generation value that runs bump when they create or delete copies) to every cached block type, so cached blocks pick up new copies and licence changes.
| Hook | Where (4.21.2 / 4.17.2) | Use |
|---|---|---|
smarty_block_hook_post |
Tygh\SmartyEngine\Blocks\Hook :147 / smarty_plugins/block.hook.php :143 |
Rewrites common:image (storefront only). Argument 4 is $template (4.21) / $smarty (4.17); unused. |
generate_thumbnail_file_pre |
fn.images.php :1218 / :1158 |
Appends the new thumbnail path to the hint file. |
update_image |
fn.images.php :128 / :127 |
Deletes copies, thumbnail copies and the backup of the replaced file. |
delete_image |
fn.images.php :198 / :197 |
Same, once the file is gone (shared images are kept). |
before_dispatch (static, License\Client) |
admin area and console | Licence checks and admin notices (generated). |
init_templater_post |
only while an upgrade is pending | Upgrade\Synchronizer (generated). |
All hooks exist with the same arguments in 4.17.2 and 4.21.2.
Processing
Section titled “Processing”Runner::run($seconds) (cron, the Optimise now batches, the admin background batch) takes a lock (var/kv_image_optimizer_webp/state/kv_iow_lock.txt, stale after 330 s), reads the hint file, continues the folder scan (a queue of directories, persisted between runs; a full scan starts daily or on request), then optimises waiting files (thumbnails first) until the time is up.
Optimizer::process($row) per file: ImageInfo reads the type, size, animation, EXIF orientation, colour profile and CMYK from the file header (pure PHP); Encoder writes WebP/AVIF with Imagick or GD into a temporary file, checks the file signature and renames it into place; a copy is kept only if it is at least Minimum saving smaller. With Compress original images the original is backed up (Originals::backup(), plus a .kvmeta with the written size and time), re-encoded and replaced atomically; Originals::restore() puts it back only while the file is still the version the add-on wrote.
Nothing calls external programs (exec(), shell_exec(), proc_open() are never used).
| Table / path | Contents |
|---|---|
?:kv_iow_files |
One row per source file: path (+ path_hash unique, dir_hash), grp (thumbnails, detailed, banners, other), src_size, src_mtime, width, height, webp_size, avif_size, orig_size, recompressed, excluded, status (P waiting, D optimised, S skipped, E error, X excluded), attempts, note (reason keys), updated_at. Admin, cron and console only. |
images/kv_image_optimizer_webp/ |
The copies, plus .htaccess (WebP/AVIF MIME types, no PHP, no listing) and an empty index.php. |
var/kv_image_optimizer_webp/originals/ |
Backups of compressed originals (<path> + <path>.kvmeta). |
var/kv_image_optimizer_webp/state/ |
Run lock, scan queue, last run and tick times (files, never ?:storage_data). |
var/kv_image_optimizer_webp/new.txt, generation.txt, tmp/ |
Thumbnail hints, block cache generation, encoder work files. |
Uninstall (fn_kv_image_optimizer_webp_uninstall(), runs before the uninstall queries) restores backed-up originals, deletes both folders, then the table is dropped.
License check
Section titled “License check”fn_kv_image_optimizer_webp_is_licensed() (cached per request, reads the stored state only) gates:
- the storefront rewrite (
fn_kv_image_optimizer_webp_markup_context()returnsfalse→ markup untouched, no lazy loading); - every run (
Runner::blocker()returnslicense→ cron, Optimise now and the background batch convert nothing); - the thumbnail hints.
Not gated: the admin page and statistics, the files list and its actions, Restore originals, Delete optimised copies, the cleanup in update_image/delete_image, uninstall. In the storefront License\Client::isActive() uses the current storefront host; in cron and the admin panel it means “licensed for at least one storefront”. The licence state is part of every block cache key (see above).
File map
Section titled “File map”| Path | Purpose |
|---|---|
app/addons/kv_image_optimizer_webp/addon.xml |
Settings (General, Conversion, Original images, Processing, License), table, uninstall function |
init.php |
Hook registration, synchronizer and licence blocks |
func.php |
Hook handlers, licence gate, storefront context, block cache key, settings info handlers, cron command, uninstall |
controllers/backend/kv_image_optimizer_webp.php |
Page manage (overview + files tabs); POST batch (optimize/restore/purge, AJAX), tick, retry, regenerate, unlock, files_action; console cron |
controllers/backend/kv_image_optimizer_webp_license.php |
“Check now” and cron licence check (generated) |
Tygh/Addons/KvImageOptimizerWebp/Config.php |
Typed settings |
.../Paths.php |
Storage paths, groups, exclusion patterns, URL → source mapping, storage type |
.../ImageInfo.php |
Header parser (type, size, animation, orientation, ICC, CMYK) |
.../Capabilities.php |
GD/Imagick detection, engine per format, memory check |
.../Encoder.php |
WebP/AVIF/JPEG/PNG writing with GD or Imagick |
.../Optimizer.php |
One file: copies, compression, copy deletion |
.../Originals.php |
Backups and restore |
.../Repository.php |
?:kv_iow_files queries, statistics, files list |
.../Runner.php |
Scan, runs, lock, hints, purge, generation |
.../Markup.php |
<picture> / replace rewrite, lazy loading, priority |
.../StorageData.php |
Run state in files |
.../License/Client.php, License/Ed25519.php |
Domain-bound licence client (generated) |
.../Upgrade/Synchronizer.php |
Self-healing in-place upgrades (generated) |
schemas/menu/menu.post.php |
Website → Image optimizer |
schemas/permissions/admin.post.php, vendor_multivendor.post.php |
view_settings / update_settings; no vendor access |
schemas/block_manager/block_cache_properties.post.php |
Block cache key part for every block |
design/backend/templates/addons/kv_image_optimizer_webp/views/kv_image_optimizer_webp/manage.tpl, components/files.tpl |
The admin page |
design/backend/templates/addons/kv_image_optimizer_webp/hooks/index/scripts.post.tpl |
Admin script and the background batch URL |
design/backend/templates/addons/kv_image_optimizer_webp/license/{card,status_bar,badge,info}.tpl |
Licence UI (generated) |
design/backend/css/addons/kv_image_optimizer_webp/styles.less, js/addons/kv_image_optimizer_webp/backend.js |
Admin styles (scoped .kv-iow-admin), progress loop and background batch |
var/themes_repository/responsive/css/addons/kv_image_optimizer_webp/styles.less |
.kv-iow-picture { display: contents } |
Extending
Section titled “Extending”- Other add-ons that print images through
common/image.tplget WebP/AVIF automatically. - To leave a block’s images alone, give the
<img>its ownloadingattribute (lazy loading is then not changed) or exclude its files with a pattern. define('KV_UPGRADE_SYNC_DISABLED', true);turns the upgrade synchronizer off (generic to all Kavio Labs add-ons).