=== PDEV Image Optimizer ===
Contributors: grzegorzpuszka
Donate link: https://ko-fi.com/puszkadev
Tags: webp, avif, images, optimization, thumbnails
Requires at least: 6.4
Tested up to: 7.1
Requires PHP: 8.0
Stable tag: 1.3.2
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Create WebP or AVIF copies of WordPress images locally and serve them without changing original URLs. Free, simple, and without a PRO version.

== Description ==

PDEV Image Optimizer was created because I needed a small image optimization plugin that simply did its job. I did not need a cloud dashboard, a subscription, or a long list of advanced settings. I also did not want basic features to stop working behind a paywall after installing the plugin.

This plugin is completely free and will remain free. There is no PRO version, no limited free plan, no account, and no feature unlock hidden in the settings.

= What does the plugin do? =

PDEV Image Optimizer creates WebP or AVIF copies of images from the WordPress Media Library. It can convert new uploads automatically and process an existing library in small batches that can be stopped and continued later.

You only choose:

* WebP or AVIF as the output format.
* Which source formats should be converted: JPEG, PNG, GIF, or WebP where applicable.
* Conversion quality.
* Whether new uploads and images from the active theme should be processed.

The plugin also includes thumbnail scanning and regeneration, preview-first cleanup of obsolete PDEV-generated files, storage savings statistics, conflict detection, optional Cloudflare support, and a detailed system report for troubleshooting. The Settings overview explains failed checks and links directly to the action needed to resolve each problem.

= Main features =

* Local WebP and AVIF conversion with Imagick or GD.
* Automatic conversion of new uploads and WordPress thumbnails.
* Restartable optimization of the existing Media Library.
* Optional optimization of supported images from the active theme.
* Thumbnail scan, missing-thumbnail repair, full regeneration, and obsolete-file cleanup.
* Registry-backed cleanup that previews count and size before deleting only verified `.pio.webp` and `.pio.avif` outputs, either just the obsolete ones or every generated file.
* Per-image safety limits that skip unsafe files without stopping the whole batch.
* Storage and estimated transfer savings statistics.
* Apache/LiteSpeed `.htaccess` delivery and generated Nginx configuration.
* General image-plugin and rewrite-rule conflict detection.
* Optional Cloudflare Free-compatible cache integration.
* Detailed privacy-safe system report with copy and JSON export.
* Clear Settings overview with tested encoder support, server requirements, delivery status, and conflict checks.
* Actionable recovery instructions and a live HTTP test for Apache/LiteSpeed and Nginx delivery.
* Error history from the last 24 hours, limited to 50 entries.
* No external conversion service, tracking, subscription, paywall, or PRO version.

= How does it work? =

1. WordPress stores an image such as `photo.jpg` and usually creates thumbnail files such as `photo-768x512.jpg`.
2. PDEV Image Optimizer uses Imagick, or GD as a fallback, to create an optimized file next to each source file. The file is named `photo.jpg.webp`, `photo.jpg.avif`, or for example `photo-768x512.jpg.webp`.
3. The original image is not deleted, renamed, or replaced. WordPress content continues to use the original URL ending in `.jpg`, `.png`, `.gif`, or `.webp`.
4. When a browser requests that original URL, the web server checks the browser's`Accept` header. If the browser supports the selected modern format and the sidecar file exists, the server returns the WebP or AVIF file instead.
5. A browser without support receives the untouched original image.

On Apache and compatible LiteSpeed servers, the plugin adds a clearly marked `PDEV Image Optimizer` block to `.htaccess` inside the uploads directory. If theme image optimization is enabled, it also manages a marked block in the active theme directory. The block uses rewrite rules, sets the correct MIME type, and adds `Vary: Accept` so caches know that one URL can return different file formats.

On Nginx, WordPress cannot safely edit the server configuration. PDEV Image Optimizer therefore shows ready-to-copy `map` and `location` blocks in **System status**. A server administrator must add them to the Nginx configuration and reload Nginx.

The Settings overview includes an optional live delivery test. It creates a temporary one-pixel source and optimized sidecar inside uploads, requests the source URL with the appropriate `Accept` header, verifies the returned HTTP status and `Content-Type`, and immediately removes both test files. The test runs only when an administrator clicks **Test image delivery**.

Conversion and delivery are separate steps. If WebP or AVIF files exist on disk but the server rules are missing or ignored, conversion succeeded but visitors will still receive the original files. Check **System status** when this happens.

= Server requirements =

The plugin needs both an image conversion library and working web-server rules.
Installing and activating the plugin cannot add missing PHP extensions or change server configuration that your hosting provider has disabled.

Required for conversion:

* WordPress 6.4 or newer.
* PHP 8.0 or newer.
* Imagick or GD installed and enabled in PHP.
* The selected library must support the selected output format. WebP support does not automatically mean AVIF support.
* The WordPress uploads directory must be writable by PHP.
* Enough PHP/server memory and execution time for the size of your images.

Required for automatic delivery on Apache or LiteSpeed:

* Apache-compatible rewrite support (`mod_rewrite`).
* MIME and header support (`mod_mime` and `mod_headers`).
* `.htaccess` files must be allowed and processed for the uploads directory. On Apache this normally requires an appropriate `AllowOverride` setting.
* The uploads directory or its existing `.htaccess` file must be writable by PHP so the plugin can add its marked rules.
* If theme images are enabled, the active theme directory and its `.htaccess` file must meet the same requirements.

Required for delivery on Nginx:

* Access to the Nginx website configuration.
* Permission to add the generated `map` block to the `http` context and the generated `location` block to the correct `server` context.
* Permission to test and reload Nginx after changing its configuration.

If you use managed hosting and do not have access to these settings, ask the hosting provider whether Imagick/GD supports WebP or AVIF and whether the required Apache modules and `.htaccess` overrides are enabled. PDEV Image Optimizer cannot bypass server restrictions imposed by the hosting provider.

= Hosting resource protection and image limits =

Image conversion can use considerably more memory than the compressed source file suggests. To reduce timeouts, 503 responses, and account resource-limit errors on shared hosting, PDEV Image Optimizer applies conservative limits before and during conversion.

Default limits applied to both Imagick and GD:

* Maximum source file size: **64 MB**.
* Maximum width or height: **16,384 pixels**.
* Maximum total image size: **25 megapixels**.

Additional GD protection:

* GD conversion uses a conservative **256 MB per-request memory budget**.
* The estimate includes decoded image pixels, the source file, current PHP memory usage, and a reserved safety margin.
* A hosting provider or PHP configuration may impose a lower effective limit.

Additional Imagick protection:

* Memory limit: **128 MB**.
* Memory-map limit: **256 MB**.
* Temporary disk limit: **512 MB**.
* Processing time limit: **30 seconds**.
* Thread limit: **1 thread**.

These are safety ceilings, not resource reservations. The server may enforce lower limits, and increasing a PHP or plugin limit cannot bypass the hosting account's CPU, RAM, process, or I/O allowance.

Media Library optimization starts with one attachment per request and may use two only after several fast batches.
Slow or memory-heavy batches automatically return to one attachment. Short pauses are added between requests, and temporary HTTP 409, 429, 502, 503, and 504 responses use an increasing retry delay. Progress is saved after every attachment, so a stopped job can be continued without starting the library scan from the beginning.

One WordPress attachment can contain the original image and several thumbnail files. Processing one attachment can therefore still convert several physical files.
Thumbnail regeneration always handles one attachment per request and waits briefly before requesting the next one. Thumbnail scanning is lighter and uses batches of up to five attachments.

An image that exceeds a safety limit is not converted. It is shown as a failed item with the reason in the conversion log and error list, while the optimizer continues with the next attachment. The original image is never removed or modified. Developers can adjust the safeguards with WordPress filters, but doing so should be based on the real limits of the hosting account.

== Installation ==

1. Install and activate PDEV Image Optimizer.
2. Open **Tools > Image Optimizer > Settings** and review the Overview section.
3. Follow the instruction next to every yellow or red check.
4. Choose WebP or AVIF, source formats, and quality, then click **Save settings**.
5. On Nginx, open **System status > Nginx configuration**, copy the generated blocks into the server configuration, and reload Nginx.
6. Click **Test image delivery** in Overview. The result should confirm an `image/webp` or `image/avif` response.
7. Open **Media library** and start optimization for existing images.

Do not enable overlapping WebP/AVIF rewrite rules in more than one image plugin.

== Frequently Asked Questions ==

= Are original images deleted or replaced? =

No. The original files stay in place. PDEV Image Optimizer writes a separate sidecar file next to every converted source and WordPress continues to use the original URL.

= Why do I see WebP or AVIF files on disk but the website still sends JPEG or PNG? =

Conversion works, but delivery rules do not. On Apache/LiteSpeed, check that `.htaccess`, `mod_rewrite`, `mod_mime`, `mod_headers`, and `AllowOverride` are available. On Nginx, install the generated configuration and reload the server.
Also clear page, server, CDN, and browser caches before testing again.

= Why is AVIF unavailable? =

Your installed Imagick and GD builds decide which output formats are available.
Many servers support WebP but were compiled without AVIF support. The plugin cannot add AVIF support to PHP; the hosting provider must enable it.

= Which library is used? =

Imagick is preferred when it supports the selected output format. GD is used as a fallback. The detailed System status report shows both libraries, versions, format support, and resource limits.

= How can I test delivery? =

Open **Settings > Overview** and click **Test image delivery**. PDEV Image Optimizer creates temporary local test files, requests the original URL with the selected format in the `Accept` header, verifies the response, and removes the files immediately. A successful result confirms an `image/webp` or `image/avif` response. The last result remains visible until conversion or delivery settings change.

You can also verify a real image in browser developer tools. Select its request in the Network panel and inspect `Content-Type`. The URL may still end in `.jpg` while the response type is `image/webp` or `image/avif`; that is expected.

= Does it convert existing images and thumbnails? =

Yes. **Media library** processes the original attachment and all registered WordPress image sizes. Work is split into small restartable requests. One failed or oversized image is logged and skipped without stopping the remaining batch.

= Why was an image skipped because of a resource or safety limit? =

The compressed file size does not show how much memory is needed after decoding.
PDEV Image Optimizer skips sources larger than 64 MB, wider or taller than 16,384 pixels, or containing more than 25 megapixels. GD and Imagick also have separate memory, time, disk, and thread safeguards described in **Hosting resource protection and image limits** above. The skipped attachment remains unchanged and is listed as an error so it can be reviewed instead of silently exhausting the server.

= What are Thumbnail tools for? =

They scan the Media Library for missing registered thumbnail files and obsolete files associated with image sizes that are no longer registered. They can create missing sizes or fully regenerate thumbnails. Thumbnail regeneration itself does not create WebP or AVIF files; run Media Library optimization afterward.

= Can it optimize images stored in my theme? =

Yes. Enable active theme images in Settings. The theme directory must be readable and writable, and the web-server delivery rules must also cover that directory.
Development directories such as `node_modules`, `vendor`, `.git`, and `.svn` are excluded from scanning.

= Are animated GIF files supported? =

Animated GIF files are detected and skipped so animation is not replaced by a static image. A non-animated GIF can be converted when GIF is selected.

= Does the plugin use extra disk space? =

Yes. Original files are preserved and optimized sidecars are added next to them.
The Storage savings card shows sidecar disk usage and estimates the smaller transfer size visitors may receive.

= What is removed when I uninstall the plugin? =

Uninstalling removes the plugin options, the generated-file registry table, the plugin error log, and the `.htaccess` delivery rules. The generated `.pio.webp` and `.pio.avif` files are kept on disk by default. To remove them too, either run **Optimized file cleanup** and choose **Scan all generated files** before uninstalling, or enable **Delete generated files on uninstall** in the plugin settings. On very large sites the uninstall-time deletion is a time-limited best effort and some files may remain.

= Does it work with Cloudflare? =

Local conversion and origin delivery work without connecting an API. Without a confirmed shared-cache rule, PDEV Image Optimizer uses private-cache protection so Cloudflare does not cache the wrong format for a shared image URL.

The optional Cloudflare tab can configure a Free-compatible Cache Rule, test delivery, and purge cache. Automatic rule creation requires a zone-scoped token with **Cache Settings: Edit** and **Cache Purge: Purge**.
The standard Cloudflare WordPress token preset supports purge but does not include Cache Settings: Edit.

Credentials can optionally be defined in `wp-config.php`:

`define( 'PDEV_IMAGE_OPTIMIZER_CLOUDFLARE_ZONE_ID', 'your-zone-id' );`

`define( 'PDEV_IMAGE_OPTIMIZER_CLOUDFLARE_API_TOKEN', 'your-api-token' );`

= Does the plugin send images or usage statistics anywhere? =

No. Images are converted locally. The plugin has no telemetry or analytics endpoint. Cloudflare is contacted only when an administrator explicitly provides credentials or runs the compatibility test. The Ko-fi page opens only after the user clicks its link.

= What is included in the system report? =

The report includes WordPress, PHP, web-server, Imagick, GD, plugin settings, delivery status, writable-directory checks, Cloudflare status, optimization statistics, the last live delivery test, conflicts, thumbnail status, and recent plugin errors. Site URLs, credentials, personal data, media content, and full server paths are excluded.

= How long are plugin errors stored? =

Only errors from the last 24 hours are shown and included, with an additional maximum of 50 entries. Paths, URLs, email addresses, and image names are redacted from the support report. The log is removed when the plugin is uninstalled.

= Is there a PRO version? =

No. Every feature is free and the plugin will remain free.

== External services ==

Cloudflare integration is optional. When configured, PDEV Image Optimizer sends the Zone ID and API token to Cloudflare to manage its own Cache Rule and purge the selected zone.
The compatibility test requests one public Media Library image with different `Accept` headers and stores only technical response information. Images are not uploaded to Cloudflare by this plugin.

Cloudflare information: [Terms](https://www.cloudflare.com/website-terms/) and [Privacy Policy](https://www.cloudflare.com/privacypolicy/).

== Screenshots ==

1. Simple conversion settings for format, sources, automatic conversion, theme images, and quality.
2. Restartable Media Library optimization with live progress and error counts.
3. Thumbnail scan and regeneration tools.
4. Optional Cloudflare connection, compatibility test, and cache actions.
5. Privacy-safe System status report covering WordPress, PHP, server, Imagick, GD, delivery, and recent plugin errors.

== Support ==

Support is provided **only through the official support forum for this plugin on WordPress.org**: [PDEV Image Optimizer support forum](https://wordpress.org/support/plugin/pdev-image-optimizer/).

Support is not provided by email, through the author's website, Ko-fi, social media, private messages, or any other channel. Please use the WordPress.org forum so questions and solutions remain public and useful to other users.

Before opening a topic, check **Tools > Image Optimizer > System status**, then copy the report or export its JSON file and include the relevant details in your forum post. The report is designed to omit URLs, credentials, personal data, full server paths, and media content.

== Changelog ==

= 1.3.2 =

* [Fixed] AVIF bulk optimization could stop with an "HTTP 409" error on some servers and never recover. A single image whose AVIF encode outruns the server's memory or time limit was killing the PHP worker before it could report a failure, so the job never advanced past that image and every retry hit it again and left the optimization lock stranded. That image is now detected after the first crash, recorded as a failed image, and skipped so the rest of the library finishes; AVIF batches also process one image at a time, the encoder runs at a bounded speed (filter `pdev_image_optimizer_avif_speed`), a batch the web server kills mid-request no longer holds the lock for 90 seconds (kept fresh while running, reclaimed within 45 seconds otherwise), and the optimizer waits out a busy lock or a dropped connection instead of failing immediately. The crash-skip threshold is adjustable through `pdev_image_optimizer_max_attachment_attempts`.
* [Fixed] Large photos near the megapixel limit could fail with "cache resources exhausted" on Imagick. The Imagick pixel-cache limits are now large enough to process an image up to the safe megapixel cap, including its orientation pass, and stay adjustable through the `pdev_image_optimizer_imagick_resource_limits` filter.
* [New] Filter `pdev_image_optimizer_preferred_driver` (`gd` or `imagick`) forces which encoder is tried first. The capability probe still runs, so forcing a driver that cannot encode the chosen format falls back to the other one.
* [Fixed] After moving a site, migrating its database, or restoring from a backup, every previously generated file reported "a file with PDEV's reserved optimized-image name already exists and was not created by PDEV" and could not be optimized again. A valid WebP or AVIF sitting at the reserved `.pio` path is now treated as an earlier PDEV conversion and re-created normally (the hard refusal is kept only for a file that is not a valid image of the target format), and the ownership table is recreated automatically if a migration left it behind.
* [Changed] A competing WebP or AVIF rewrite rule from another plugin - often left in `.htaccess` after that plugin is removed - no longer disables PDEV delivery. PDEV now installs its own rules regardless and shows a warning that names the competing block, says whether the plugin that created it is still active, tells you which `# BEGIN` / `# END` block to delete when it is not, and points to the live delivery test.
* [Changed] Overview cleanup: removed the "View detailed status" button (it only opened System status, which repeats what Overview already shows); after a competing rewrite rule is detected, the live delivery test result now appears in the conflict block where the test button is, instead of only in the Image delivery row; and once that test passes, the loud competing-rule warning collapses to a short "delivery still works" note, leaving the details one click away.

= 1.3.1 =

* [Fixed] The 1.3.0 release package was incomplete: several class files were missing, which caused a fatal error (`Class "PDEV\ImageOptimizer\Rest\CleanupRoute" not found`) on sites that installed or updated to 1.3.0. This release ships the complete plugin.

= 1.3.0 =

* [Feature] Added registry-backed, preview-first cleanup for obsolete PDEV-generated WebP and AVIF files, with an optional "all generated files" mode that also clears the optimization state so images are regenerated.
* [Feature] Added a "Delete generated files on uninstall" setting; when enabled, the uninstaller removes registered `.pio.webp` / `.pio.avif` files (best effort, time-limited) while never touching originals.
* [Changed] Generated files now use the unambiguous `.pio.webp` and `.pio.avif` naming contract; legacy sidecars are no longer served or removed automatically.
* [Security] Cleanup accepts no browser-supplied paths and revalidates exact registry ownership immediately before deletion.
* [Fixed] The live delivery test no longer fails on a self-signed or mismatched certificate when the uploads URL is on this site's own host.

= 1.2.1 =

* [Release] First public build.

== Upgrade Notice ==

= 1.3.2 =
Fixes an HTTP 409 failure during AVIF bulk optimization, a "cache resources exhausted" failure on large photos, and a "reserved optimized-image name" failure after moving or migrating a site. A competing rewrite rule from another plugin now warns instead of disabling PDEV delivery.

= 1.3.1 =
Fixes a fatal error in 1.3.0 caused by missing files in the release package. Update as soon as possible if you installed or updated to 1.3.0.
