Files
h4b-image-optim/CHANGELOG.md
Henk 4cd1390a94 feat: migrate-from-smush + Picture-tag rewriter (v0.2.0)
Unblocks production use on sites previously running Smush.

migrate-from-smush:
  - Reads wp-smpro-smush-data postmeta, writes _h4b_img_optim marker
  - --dry-run / --force-rescan / --remove-smush-meta / --limit flags
  - Verified: 100 attachments migrated cleanly on dev.rds.ink,
    bulk count drops from 734 → 634

Picture_Tag rewriter:
  - Hooks the_content + post_thumbnail_html + widget_text + Elementor
    frontend + wp_get_attachment_image at priority 99
  - Wraps <img> in <picture><source avif><source webp><img></picture>
    when sibling files exist
  - Double-wrap protection via byte-range tracking of existing <picture> blocks
  - Per-image opt-out via data-no-h4b attribute
  - Cached sibling lookups per request
  - 8 edge-case tests pass

LOC: 2480 (was 1997). Adds class-cli-migrate.php (193 LOC) and
class-picture-tag.php (284 LOC).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 13:50:41 +10:00

4.5 KiB

CHANGELOG

All notable changes to h4b-image-optim will be documented here.

Format follows Keep a Changelog and Semantic Versioning.

[0.2.0] — 2026-05-19

Added migrate-from-smush + Picture-tag rewriter. The plugin is now usable end-to-end on a site that previously ran Smush — no double-processing, and WebP / AVIF actually get served to visitors.

Added

  • wp h4b-img migrate-from-smush — reads Smush's wp-smpro-smush-data postmeta, writes equivalent _h4b_img_optim markers so our bulk command skips already-optimised attachments.
    • --dry-run to see counts only
    • --force-rescan to mark for re-optimisation instead (use when migrating off Smush completely)
    • --remove-smush-meta to delete the Smush postmeta after migration
  • Picture_Tag rewriter (the_content + post_thumbnail_html + widget_text + Elementor frontend + wp_get_attachment_image filters at priority 99). Wraps <img> tags with <picture><source type="image/avif"><source type="image/webp"><img></picture> when sibling files exist on disk.
    • Skips images already inside a <picture> block (double-wrap protection via byte-range tracking)
    • Skips images with data-no-h4b attribute (per-image opt-out)
    • Resolves siblings either alongside the JPG (foo.jpg.webp) or in Smush's wp-content/smush-webp/ mirror tree
    • Caches sibling lookups per request to keep it cheap
    • Preserves srcset, sizes, alt, class, and all other original <img> attrs

Verified

  • migrate-from-smush: 100 attachments migrated cleanly on dev.rds.ink
  • bulk count correctly drops after migration (734 → 634)
  • Picture_Tag: 8 edge-case tests pass (no siblings, multiple images, opt-out, srcset preservation, external URLs, no <img>, existing <picture>, mixed)

[0.1.0] — 2026-05-19

Initial MVP. Replaces Smush Pro's optimisation pipeline without the grey-wash bug. CLI-only in this release (admin UI comes in 0.2).

Added

  • Plugin scaffold with PSR-12-style namespaced classes (H4B\ImageOptim\*)
  • Optimizer — in-place JPG / PNG re-encode using Imagick + jpegoptim / pngquant
    • ICC profile preservation (the Smush-bug fix) via bundled sRGB v4 profile fallback
    • 4:4:4 chroma subsampling for large images; 4:2:0 for small ones
    • Configurable size threshold (min_optimise_bytes, default 20 KB) to skip thumbnails that re-encoding would inflate
    • Atomic file replacement with ownership preservation
    • GPS EXIF stripping on by default for privacy
    • EXIF orientation applied before encode
  • Format_Generator — WebP (synchronous) + AVIF (queued via WP-Cron) siblings
  • Uploader_Hook — intercepts wp_generate_attachment_metadata
  • Attachment_Meta — per-attachment optimisation history in _h4b_img_optim
  • Rescue_Detector — PHP port of the Python grey-wash detector
  • Originals backup to wp-content/h4b-img-originals/ with 90-day cron prune
  • WP-CLI commands:
    • wp h4b-img status — tool detection + settings dump
    • wp h4b-img optimise --id=<n> — single-attachment optimise (+ --dry-run)
    • wp h4b-img bulk — bulk-optimise unprocessed attachments (+ --limit, --force, --dry-run, --batch, --pause)
    • wp h4b-img rescue — scan + optionally repair Smush-mangled JPGs from their .webp siblings (+ --scan, --apply, --min-severity, --csv, --manifest)
  • uninstall.php — clean removal of plugin options + cron, preserves user data (backups + .webp/.avif siblings + optimisation postmeta)

Required system tools (AlmaLinux 9 / Debian 13)

Tool AlmaLinux Debian
cwebp libwebp-tools webp
jpegoptim jpegoptim jpegoptim
cjpeg / jpegtran libjpeg-turbo-utils libjpeg-turbo-progs
avifenc libavif-tools libavif-bin
pngquant pngquant pngquant
optipng optipng optipng

Known limitations

  • No admin settings page (CLI/wp option only)
  • No Picture-tag rewriting on the_content (Smush still serving WebPs)
  • No .htaccess content-negotiation fallback
  • No migrate-from-smush command yet
  • No PHPUnit test suite yet

Verified against

  • AlmaLinux 9.7 / PHP 8.4.21 / Imagick 3.8.1 (production)
  • Debian 13 / PHP 8.4 / wordpress:php8.4-apache (dev container)
  • Tested on 20 rds.ink attachments in bulk mode: 487 KB saved (10.4%), 0 errors
  • Rescue mechanic verified end-to-end on the WorkingAsOne_horse900-800x524.jpg fixture