Skip to content

Developer notes

  • 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>.webp and <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_post rewrites the output of the template hook common:image (core common/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 maps src/srcset (and data-src/data-srcset of 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 three stat calls 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_image and delete_image also 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 Accept header 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 to var/kv_image_optimizer_webp/new.txt when the core generates a new thumbnail (a hint for the next run).
  • Block cache: schemas/block_manager/block_cache_properties.post.php adds the callable handler kv_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.

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.

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() returns false → markup untouched, no lazy loading);
  • every run (Runner::blocker() returns license → 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).

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 }
  • Other add-ons that print images through common/image.tpl get WebP/AVIF automatically.
  • To leave a block’s images alone, give the <img> its own loading attribute (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).