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>
94 lines
4.5 KiB
Markdown
94 lines
4.5 KiB
Markdown
# CHANGELOG
|
|
|
|
All notable changes to **h4b-image-optim** will be documented here.
|
|
|
|
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
|
## [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
|