=== AVIF Local Support ===
Contributors: ddegner
Tags: avif, images, performance, media, optimization
Requires at least: 6.8
Tested up to: 7.0
Stable tag: 0.7.0
Requires PHP: 8.3
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

High-quality AVIF image conversion for WordPress — local, quality-first.

== Description ==

Built by a [Boston photographer](https://www.daviddegner.com) for site owners who care about visual quality and full control. This plugin prioritizes **image quality** over everything else — no subscriptions, no external services.

== Features ==

- **Local Processing** — All conversion happens on your server. No subscriptions or external API calls. Works great on a shared CPU with 2GB RAM.
- **Quality First** — Uses LANCZOS resizing, preserves ICC color profiles, and keeps EXIF/XMP/IPTC metadata intact.
- **Fully Tunable** — Control quality (0–100), speed (0–10), chroma subsampling (4:2:0, 4:2:2, 4:4:4), and bit depth (8/10/12-bit).
- **Smart Fallback** — Serves AVIF to supported browsers, JPEG to everyone else via picture elements.
- **Automatic Conversion** — Convert on upload or via daily scheduled background scans.
- **LQIP Placeholders** — Generate ThumbHash-based low-quality image placeholders for smooth loading.

== How It Works ==

**Front end:** The plugin wraps your img tags in picture elements with an AVIF source. Browsers that support AVIF load the smaller, higher-quality file — others gracefully fall back to JPEG.

**Conversion:** Uses ImageMagick CLI (fastest), Imagick PHP extension (high quality), or GD Library (fallback) to convert JPEGs to AVIF on upload or via background jobs.

**LQIP:** Generates compact (~30 byte) ThumbHash placeholders that display instantly while images load.

== Installation ==

1. Upload to `/wp-content/plugins/avif-local-support` or install via **Plugins → Add New**
2. Activate the plugin
3. Navigate to **Settings → AVIF Local Support**

= Requirements =

- **PHP:** 8.3 or later
- **WordPress:** 6.8 or later
- **Recommended:** Imagick extension with AVIF-enabled ImageMagick

== Server Setup ==

The plugin supports three conversion engines, in order of preference:

= ImageMagick CLI (Fastest, Recommended) =

Uses the ImageMagick command-line binary directly:

- **System binary:** ImageMagick 7.x built with HEIF/AVIF support (via libheif)
- **No PHP extension required**
- **Benefits:** Fastest performance, LANCZOS resizing, full metadata preservation (EXIF, XMP, IPTC, ICC)
- **Typical paths:** `/usr/bin/magick`, `/usr/local/bin/magick`, or Homebrew on macOS

To verify AVIF support:

    magick -list format | grep -i avif

= Imagick PHP Extension (High Quality) =

Uses the PHP Imagick extension:

- **PHP extension:** imagick
- **System libraries:** ImageMagick built with HEIF/AVIF support (via libheif)
- **Benefits:** LANCZOS resizing, full metadata preservation (EXIF, XMP, IPTC, ICC), color profile handling

To install on Ubuntu/Debian:

    apt install php-imagick imagemagick libheif-dev

= GD Library (Fallback) =

Uses PHP's built-in GD library:

- **PHP extension:** gd built with AVIF support (provides imageavif on PHP 8.1+)
- **Note:** Some distro builds omit AVIF support; limited metadata preservation

= MIME Type Configuration =

Ensure your web server is configured to serve .avif files as image/avif.

= Documentation =

- [ImageMagick installation](https://imagemagick.org/script/download.php)
- [PHP Imagick installation](https://www.php.net/imagick)
- [PHP GD installation](https://www.php.net/manual/en/image.installation.php)
- [ImageMagick format support](https://imagemagick.org/script/formats.php)

= Need help with setup? =

If you're not sure what to install or upgrade, copy your **Server Diagnostics** from the plugin status/tools screen (or run `wp avif status --format=json`) and paste it into an LLM.

Example prompt:

    I need AVIF support for WordPress. Based on this diagnostics output, give me step-by-step commands to install or upgrade ImageMagick, libheif, and PHP Imagick on my server.

After applying changes, verify with:

    wp avif status
    magick -list format | grep -i avif

== WP-CLI Commands ==

Manage AVIF conversions from the command line.

= Status =

Show system status and AVIF support diagnostics:

    wp avif status
    wp avif status --format=json

= Convert =

Convert JPEG images to AVIF format:

    wp avif convert --all
    wp avif convert 123
    wp avif convert --all --dry-run

Options:

- `<attachment-id>` — Specific attachment ID to convert
- `--all` — Convert all attachments missing AVIF versions
- `--dry-run` — Show what would be converted without actually converting

= Statistics =

Show AVIF conversion statistics:

    wp avif stats
    wp avif stats --format=json

= Logs =

View or clear conversion logs:

    wp avif logs
    wp avif logs --limit=50
    wp avif logs --clear

Options:

- `--clear` — Clear all logs
- `--limit=<number>` — Number of logs to show (default: 20)

= Delete =

Delete AVIF files for an attachment or all attachments:

    wp avif delete 123
    wp avif delete --all --yes

Options:

- `<attachment-id>` — Attachment ID to delete AVIF files for
- `--all` — Delete all AVIF files in the media library
- `--yes` — Skip confirmation prompt when using --all

= LQIP Commands =

Manage LQIP (ThumbHash) placeholders:

    wp lqip stats
    wp lqip generate --all --force
    wp lqip generate 123
    wp lqip delete --all --yes

For more information, visit [wp-cli.org](https://wp-cli.org/).

== Frequently Asked Questions ==

= Does this modify my original JPEGs? =

No. AVIF files are created alongside your existing images. Your originals remain untouched.

= Will this slow down uploads? =

If "Convert on upload" is enabled, uploads may take slightly longer. You can disable this and use scheduled background conversion instead.

= Do I need Imagick? =

Recommended but not required. Imagick provides the best quality and preserves metadata/color profiles. The plugin falls back to GD if unavailable.

= Does it track users or send data externally? =

No. Zero tracking, zero external calls. Everything runs locally.

= Why do I see "High risk of memory exhaustion"? =

The plugin estimates memory before processing to prevent crashes. Try switching to "ImageMagick CLI" engine, increasing PHP memory_limit, or checking "Disable memory check" in settings.

= AVIF conversions produce empty files on LiteSpeed? =

This is caused by libheif 1.12.0 crashing in LiteSpeed's restricted environment. Upgrade libheif to 1.15+ to fix. See the [WordPress.org FAQ](https://wordpress.org/plugins/avif-local-support/#faq) for build instructions.

= ImageMagick CLI not detected on LiteSpeed/CyberPanel? =

LiteSpeed's open_basedir restriction prevents PHP from detecting executables outside allowed paths. The binary may still work — try setting the path manually in settings.

== Screenshots ==

1. **AVIF Images** — Configure AVIF delivery, conversion quality, speed, and engine settings
2. **LQIP** — Configure ThumbHash generation and display behavior
3. **Tools** — Run AVIF/LQIP bulk tools and review server support diagnostics
4. **About** — Quick reference and version info

== Changelog ==

= 0.7.0 =

- Fix: LQIP (ThumbHash) placeholders were decoded at the wrong aspect ratio and rendered as distorted slivers; placeholders now match each image's shape.
- Fix: LQIP placeholders no longer stay hidden for images that are not wrapped in a `<picture>` element.
- Fix: Failed conversions no longer leave tiny invalid `.avif` files that could be served to visitors and were never regenerated; such files are now cleaned up and reconverted.
- Fix: "Delete All AVIF" no longer erases LQIP placeholder data, which is managed independently.
- Fix: LQIP generation now succeeds for attachments with missing or broken metadata by falling back to the original file.
- Enhancement: Bulk AVIF conversion and LQIP generation now run as resumable, time-sliced background jobs, preventing request timeouts and cron stalls on large media libraries.
- Enhancement: Removed a database write that occurred on every front-end request from the AVIF file-existence cache.
- Enhancement: Unified the Tools interface — consistent progress indicators that end on a completion checkmark, clearer status messages, and accurate stopped/queued states for scans.
- Enhancement: Renamed settings tabs to "AVIF Settings" and "LQIP Settings" and removed redundant in-tab headings.
- Chore: Made filesystem-scan status messages translatable and removed an unused bundled admin script.

= 0.6.4 =

- Feature: Added a filesystem scanner for JPEGs under uploads that are not represented in the Media Library, including WP-CLI and admin Tools support.
- Enhancement: Added WordPress AVIF compatibility diagnostics to `wp avif status --format=json` and Site Health debug data.
- Chore: Confirmed WordPress 7.0 compatibility and hardened production package exclusions for development metadata.

= 0.6.3 =

- Fix: Lightbox/slideshow links now correctly rewrite from JPEG to AVIF when the image was already wrapped in a `<picture>` element by another plugin (e.g. photo-collage). Previously the `<a>` href rewriting was skipped for images inside `<picture>`, causing lightboxes to load full-size JPEGs instead of AVIFs.

= 0.6.2 =

- Chore: Added a commit-based beta build workflow that publishes prerelease ZIPs to GitHub Releases.
- Chore: Kept stable release builds tag-based and guarded WordPress.org deploy so `beta-*` tags are ignored.

= 0.6.1 =

- Fix: Clear Logs now reliably clears stored logs and prevents stale long-running processes from repopulating old entries.
- Enhancement: Logs panel now refreshes from server state after clearing, so UI always matches stored data.
- Enhancement: Clear Logs button is temporarily disabled while the clear request is in progress to prevent duplicate requests.
- Chore: Uninstall now removes the logs-generation option used by the clear-logs protection.

= 0.6.0 =

- Fix: Removed redundant on-upload AVIF conversion hook path to avoid duplicate work and keep upload conversion predictable.
- Fix: Improved daily scheduling behavior so overdue events run instead of being pushed to tomorrow, and on-demand AVIF scans always run regardless of schedule toggle state.
- Feature: Added stop control for bulk LQIP generation (REST endpoint + transient stop signal + admin status updates).
- Enhancement: Standardized admin LQIP wording and labels, including a short LQIP explanation at the top of the LQIP tab.
- Fix: Uninstall now clears LQIP stop transient and uses `delete_post_meta_by_key()` for ThumbHash metadata cleanup.
- Chore: Plugin Check hardening for release by excluding non-distribution files from check scope and clearing stray `.DS_Store` files.

= 0.5.23 =

- Feature: Added an AVIF Settings Playground for real JPEG/AVIF preview comparisons and one-click apply of tested settings.
- Feature: Expanded Tools with dedicated LQIP bulk generation/deletion controls and progress/status feedback.
- Enhancement: Refreshed admin UX across tabs (clearer labels, advanced sections, improved diagnostics and logs layout).
- Enhancement: Updated WordPress.org screenshots to match the current AVIF, Placeholders, Tools, and About screens.
- Fix: Plugin Check hardening for release by escaping help-tip output safely and using `wp_delete_file()` in preview cleanup paths.

= 0.5.22 =

- Fix: AVIF Delete All now removes only plugin companion AVIF files for JPEG attachments, preventing deletion of user-uploaded AVIF originals.
- Fix: CSS background AVIF overrides now keep a JPEG fallback and use `image-set(...)` so non-AVIF browsers still render backgrounds.
- Fix: ThumbHash decoder aspect-ratio extraction corrected (`h16 & 7`) to match the upstream reference implementation.
- Fix: Restore defaults now resets background-image and all LQIP settings in addition to core AVIF settings.
- Fix: Corrected malformed HTML in the Tools diagnostics table around the schedule-time display.
- Fix: Clarified Tools count labels to match scope: AVIF now shows file-level totals as "JPEG Files" (originals + generated sizes), and LQIP shows attachment-level totals as "Media Items" (plus clearer "Without AVIF/LQIP" and "AVIF files" progress wording).

= 0.5.21 =

- Enhancement: ThumbHash input increased to 100px for richer LQIP placeholders.
- Fix: AVIF srcset now correctly lists all responsive sizes by running after WordPress adds srcset attributes.
- Fix: Single AVIF images now include width descriptors for proper responsive selection.
- Refactor: Removed redundant `render_block` filter; unified image processing in `the_content` filter.

= 0.5.20 =

- Fix: Instant reveal now waits for `img.decode()` to prevent white flash on fast-loading images.

= 0.5.19 =

- Refactor: Simplified LQIP fade transition — removed blur filter and scale animation.
- Fix: Eliminated white flash during LQIP-to-image transition by ensuring image is fully visible before removing placeholder.
- Fix: Fast-loading images now appear instantly without the 400ms fade delay.
- Cleanup: Removed unused per-image load duration tracking.

= 0.5.18 =

- Feature: LQIP Generate All now shows real-time progress counter, status text, and stop button.
- Feature: Unified spinner/status UI for both AVIF and LQIP tools panels.
- Fix: "AVIF conversion available" badge now correctly shows "Yes" when engines report support.
- Fix: AVIF Delete All button now correctly re-enables Generate All button after completion.

= 0.5.17 =

- Fix: LQIP background now correctly clears for already-loaded/cached images.

= 0.5.16 =

- Feature: Restored LQIP background cleanup after image load.
- Feature: Added "Pixelated placeholders" option to display ThumbHash as sharp pixels.
- Enhancement: Improved LQIP transition — blur-up effect with scale animation.
- Change: Transition updated to 400ms ease-out for smoother reveal.

= 0.5.15 =

- Enhancement: Tuned LQIP fade thresholds based on human perception research.
- Change: Page load window increased to 2 seconds (covers initial render).
- Change: Individual load duration increased to 200ms (perception threshold).

= 0.5.14 =

- Fix: WordPress Plugin Check compliance — proper escaping for inline scripts/styles.
- Fix: Replace `strip_tags()` with `wp_strip_all_tags()` in BackgroundImages.
- Fix: Prefix global variables with plugin prefix.
- Chore: Remove `.DS_Store` files from repository.

= 0.5.13 =

- Refactor: Simplified LQIP fade logic by removing background cleanup step.

= 0.5.12 =

- Feature: LQIP operations now log successes, failures, and summaries to the Logs panel.
- Fix: LQIP stats now correctly validate metadata structure, matching generation skip logic.
- Fix: Add object cache clearing before LQIP generation to prevent stale data on servers with persistent caching.
- Fix: Prevent false positive \"success\" reports in `wp lqip generate` when generation fails silently but stale data exists.
- Fix: Remove deprecated `imagedestroy()` calls for PHP 8.0+ compatibility.
- Refactor: Consolidate LQIP generation logic into shared helper for consistency between Admin UI and CLI.

= 0.5.11 =

- Fix: Critical fix for `wp lqip generate --force` option.
- Fix: `wp lqip delete --all` now correctly clears object cache to prevent stale stats.

= 0.5.9 =

- Feature: Added `--force` option to `wp lqip generate` command to force regeneration of LQIPs.

= 0.5.8 =

- Fix: Resolved "Insufficient memory" error when generating LQIP for high-resolution images by optimizing ImageMagick loading.

= 0.5.7 =

- Feature: CSS background image AVIF support — replaces JPEG background images with AVIF versions. Thanks to [David C.](https://www.rankxpress.com)
- Feature: Works with page builders (Elementor, Divi, Beaver Builder, WPBakery, Bricks, etc.)
- Feature: New setting "Serve AVIF for CSS backgrounds" under AVIF serving options
- Fix: Versioned image URLs (e.g., `image.jpg?ver=123`) now correctly detected and replaced
- Fix: Query string stripping for CSS file path resolution
- Security: Sanitize CSS selectors to prevent XSS injection

= 0.5.6 =

- Enhancement: Smart fade logic — only apply fade transition for slow-loading images
- Enhancement: Images loading within 1 second of page load display instantly (no fade)
- Enhancement: Cached/fast-loading images skip fade for snappier feel

= 0.5.5 =

- Feature: Added "Fade in images" option to smoothly transition from LQIP to full image
- Fix: Used img.decode() to prevent white flash during LQIP fade transition
- Fix: CSS selector now correctly handles both picture wrapper and standalone img cases

= 0.5.4 =

- Feature: Added optional smooth fade-in for LQIP images
- Translations: Added German, Italian, Japanese, Portuguese (Brazil), and Russian translations
- Enhancement: Updated translations for Spanish, French, Hindi, and Chinese
- Fix: `wp lqip generate --all` now correctly processes all eligible images
- Fix: `wp lqip stats` accurately counts all supported image types
- Fix: LQIP JavaScript is now correctly excluded when feature is disabled
- Fix: Improved error logging for LQIP generation failures

= 0.5.3 =

- Fix: Added missing LQIP options to plugin activation (thumbhash_size, generate_on_upload, generate_via_schedule)
- Fix: Added missing LQIP options to uninstall cleanup for complete data removal
- Fix: Properly minified thumbhash-decoder.min.js (62% size reduction)
- Fix: Excluded developer documentation from WordPress plugin distribution

= 0.5.2 =

- Feature: Bundled ThumbHash library — no Composer dependency required on deployment
- Enhancement: Improved LQIP generation with better error handling, progress reporting, and memory management
- Enhancement: Added `--limit` and `--verbose` options to `wp lqip generate` command
- Fix: Resolved hanging issue in `wp lqip generate --all` command with better error handling and progress output
- Fix: Clear error messages when ThumbHash library is unavailable

= 0.5.1 =

- Fix: Improved error handling and logging for ThumbHash generation
- Enhancement: WP-CLI now warns if LQIP feature is disabled in settings
- Enhancement: Better diagnostics for missing source files during LQIP generation

= 0.5.0 =

- Feature: LQIP (Low Quality Image Placeholder) using ThumbHash for smooth image loading
- Feature: WP-CLI commands for LQIP management (`wp lqip stats`, `wp lqip generate`, `wp lqip delete`)
- Feature: Dedicated LQIP settings tab with enable/disable toggle
- Enhancement: Reorganized admin UI with combined AVIF Tools section
- Enhancement: Consistent stat labels across AVIF and LQIP tools (Images/With/Without)
- Enhancement: Renamed "Test conversion" to "Test AVIF Conversion" for clarity
- Enhancement: Removed beta labels from LQIP feature
- Fix: LQIP stats now correctly count all supported image types (JPEG, PNG, GIF, WebP)
- Dev: Auto-fixed 6,152+ PHPCS issues for WordPress coding standards compliance

= 0.4.9 =

- Fix: WordPress Plugin Check compliance — proper escaping, Yoda conditions, and PHPCS ignores
- Fix: Improved uninstall cleanup with object cache awareness
- Dev: Code formatting aligned with WordPress coding standards

= 0.4.8 =

- Fix: Resolved logging pipeline issues where REST API couldn't retrieve logs due to `is_admin()` check
- Fix: Fixed upload test timeout by temporarily disabling synchronous AVIF conversion during test uploads
- Fix: Improved AJAX feedback for log operations (clear/refresh)
- Docs: Updated minimum requirements to WordPress 6.8 and PHP 8.3
- Docs: Cleaned up README header format for WordPress.org compatibility
- Docs: Removed donate link from readme
- Dev: Added WordPress stubs for improved IDE support

= 0.4.7 =

- Enhancement: Improved time formatting in conversion progress display (hh:mm:ss format)
- Enhancement: CLI code formatting improvements
- Fix: Corrected contributor username in readme

= 0.4.6 =

- Docs: Added WordPress.org metadata headers
- Docs: Updated tested up to WordPress 6.9

= 0.4.5 =

- Fix: Corrected "Upload & Test" status display issues (spinner visibility, status text alignment)
- Fix: `wp avif delete` command now correctly reports success/failure counts and handles permission errors
- Fix: `wp avif convert` command output now includes count of missing AVIFs
- Enhancement: Added GitHub Action for automated release creation

= 0.4.4 =

- Feature: Fully asynchronous "Upload & Test" conversion to prevent timeouts on large images
- Enhancement: Re-architected test conversion to use sequential polling
- Enhancement: Admin UI modularized with template-based architecture
- Optimization: Removed unused `vendor` storage and legacy dependencies, reducing plugin size
- Fix: Restored robust queue rendering for test results

= 0.4.3 =

- Added WP-CLI commands: status, convert, stats, logs, delete
- Refactored admin interface with modular architecture
- Improved logging and environment diagnostics

= 0.4.2 =

- Auto-detection for ImageMagick CLI in "Auto" mode
- REST API replaces admin-ajax for better performance
- Smart -define namespace probing (heic/avif)
- Tested with WordPress 6.9

= 0.4.1 =

- Compatibility: Tested up to WordPress 6.9

= 0.4.0 =

- Major refactor: strict types, DTOs, dedicated Encoder classes
- Optimized frontend HTML parsing
- Enhanced CLI execution and error handling
- Composer support (PSR-4 ready)

= 0.3.x =

- Environment variable injection for restricted PHP environments
- Original image source handling fixes
- Engine priority: CLI, Imagick, GD

= 0.2.x =

- ImageMagick CLI support with auto-detection
- Memory pre-check to prevent fatal errors
- Logs panel with detailed entries
- Lightbox anchor rewriting
- Chroma subsampling and bit depth options

= 0.1.x =

- Initial release with Imagick/GD support
- ICC profile preservation
- EXIF orientation handling
- Basic admin interface

See [GitHub releases](https://github.com/ddegner/avif-local-support/releases) for complete version history.

== Contributing ==

Contributions welcome! Please submit issues and pull requests on [GitHub](https://github.com/ddegner/avif-local-support).

== License ==

GPL v2 or later — [View License](https://www.gnu.org/licenses/gpl-2.0.html)
