Title: EffortLess Simple Image Optimiser
Author: domclic
Published: <strong>28. 3. 2026</strong>
Last modified: 28. 3. 2026

---

Prohledat pluginy

![](https://s.w.org/plugins/geopattern-icon/effortless-simple-image-optimiser.svg)

# EffortLess Simple Image Optimiser

 Autor: [domclic](https://profiles.wordpress.org/domclic/)

[Stáhnout](https://downloads.wordpress.org/plugin/effortless-simple-image-optimiser.1.0.56.zip)

 * [Podrobnosti](https://cs.wordpress.org/plugins/effortless-simple-image-optimiser/#description)
 * [Hodnocení](https://cs.wordpress.org/plugins/effortless-simple-image-optimiser/#reviews)
 *  [Instalace](https://cs.wordpress.org/plugins/effortless-simple-image-optimiser/#installation)
 * [Vývojáři](https://cs.wordpress.org/plugins/effortless-simple-image-optimiser/#developers)

 [Podpora](https://wordpress.org/support/plugin/effortless-simple-image-optimiser/)

## Popis

**Effortless Simple Image Optimiser** hooks directly into the WordPress Media Library
upload pipeline and compresses, resizes and (optionally) converts images the moment
they are uploaded — all using the built-in PHP GD extension.

#### Features

 * **JPEG compression** — re-encodes JPEGs at a configurable quality level (default:
   82). GD strips EXIF metadata automatically, further reducing file size.
 * **PNG compression** — applies lossless GD compression to PNG files.
 * **PNG  JPEG conversion** — converts opaque (non-transparent) PNGs to JPEG for
   significant space savings. Transparent PNGs are always kept as PNG.
 * **Image resizing** — scales down images that exceed a configurable maximum width
   or height while maintaining the original aspect ratio.
 * **WebP generation** — optionally saves a `.webp` sidecar file alongside every
   optimised image (requires GD compiled with WebP support).
 * **Zero external dependencies** — no API keys, no third-party services, no composer
   packages.
 * **Graceful degradation** — if GD is not available the plugin skips processing
   and logs a notice; uploads are never blocked.

#### Settings

Navigate to **Settings  Image Optimiser** to configure:

 * Enable / disable automatic optimisation on upload
 * JPEG quality (1–100, default 82)
 * Enable PNG  JPEG conversion
 * Enable WebP sidecar generation + WebP quality
 * Enable / disable resizing
 * Maximum width in pixels (default 1920)
 * Maximum height in pixels (default 1920)

#### Requirements

 * PHP 7.4 or higher
 * PHP GD extension (enabled on virtually all shared hosting)
 * WordPress 5.9 or higher

## Instalace

**From the WordPress admin (recommended)**

 1. Go to **Plugins  Add New**.
 2. Search for _Effortless Simple Image Optimiser_.
 3. Click **Install Now**, then **Activate**.
 4. Configure the plugin at **Settings  Image Optimiser**.

**Manual installation**

 1. Download the plugin zip file.
 2. Unzip and upload the `effortless-simple-image-optimiser` folder to `/wp-content/
    plugins/`.
 3. Activate the plugin from the **Plugins** screen.
 4. Go to **Settings  Image Optimiser** to configure your preferences.

## Nejčastější dotazy

### Does the plugin require an API key or external account?

No. Everything is processed locally using the PHP GD library that ships with PHP.

### Will my existing images be optimised?

Not automatically. The plugin only processes images at the time of upload. To re-
optimise existing images you will need to re-upload them or use a separate bulk-
processing tool.

### Is the original image kept as a backup?

By default the plugin overwrites the original file with the optimised version. Make
sure you keep your own backups if you need to recover originals.

### What happens if GD is not installed?

The plugin fails gracefully — uploads proceed normally, a notice is logged to the
PHP error log, and a warning is displayed on the settings page.

### Why does PNG  JPEG conversion only apply to some PNGs?

PNGs that contain any transparent pixels are never converted to JPEG because JPEG
does not support transparency. The plugin samples the image to detect transparency
before converting.

### Does the plugin support WebP uploads?

Yes. Uploaded WebP images are re-compressed using the configured WebP quality setting.

### Will this slow down my site or uploads?

Processing is synchronous and happens during the upload request. On typical shared
hosting the overhead is negligible for standard web images (< 5 MB). Very large 
files may add a second or two.

## Recenze

Pro tento plugin nejsou žádné recenze.

## Autoři

EffortLess Simple Image Optimiser je otevřený software. Následující lidé přispěli
k vývoji tohoto pluginu.

Spolupracovníci

 *   [ domclic ](https://profiles.wordpress.org/domclic/)

[Přeložte “EffortLess Simple Image Optimiser” do svého jazyka.](https://translate.wordpress.org/projects/wp-plugins/effortless-simple-image-optimiser)

### Zajímá vás vývoj?

[Prohledejte kód](https://plugins.trac.wordpress.org/browser/effortless-simple-image-optimiser/),
podívejte se do [SVN repozitáře](https://plugins.svn.wordpress.org/effortless-simple-image-optimiser/),
nebo se přihlaste k[ odběru protokolu vývoje](https://plugins.trac.wordpress.org/log/effortless-simple-image-optimiser/)
pomocí [RSS](https://plugins.trac.wordpress.org/log/effortless-simple-image-optimiser/?limit=100&mode=stop_on_copy&format=rss).

## Přehled změn

#### 1.0.56

 * Fix: Prefix all global variables in uninstall.php to comply with WordPress plugin
   coding standards.

#### 1.0.55

 * Revert: Removed pixel-scan cap on PNG transparency detection — every pixel is
   checked to ensure even a single transparent pixel (icons, logos) keeps the image
   as PNG.

#### 1.0.54

 * Security: Nonce is now verified before accessing `$_GET` parameters on the settings
   page.
 * Security: `.htaccess` write in originals directory uses exclusive file locking
   and logs errors on failure.
 * Security: `render_env_row()` now escapes output with `wp_kses_post()` instead
   of relying on caller discipline.
 * Performance: All unbounded `posts_per_page => -1` queries replaced with paginated
   batching via `elsio_get_all_ids()` to prevent memory exhaustion on large sites.
 * Performance: Dedup scan primes the post meta cache in batches, eliminating N+
   1 queries.
 * Fix: Stale backup detection — if backup meta exists but the file is missing on
   disk, a fresh backup is created instead of silently skipping.
 * Improvement: WordPress 5.9+ version enforced on activation with a clear error
   message.
 * Improvement: Direct database queries in URL replacer and dedup now invalidate
   WordPress object cache (`clean_post_cache()` / `wp_cache_delete()`) after updates.

#### 1.0.52

 * Fix: `preg_replace()` null return now triggers a WP_Error instead of silently
   writing an empty restore path during format-changed restores (PNGJPEG or vice
   versa).
 * Fix: Restored file is validated after `copy()` — a 0-byte write now returns a
   WP_Error and the file is removed rather than silently replacing the live image.
 * Fix: Bulk optimisation aborts with an error response when the pre-optimisation
   backup cannot be created, preventing data loss.
 * Fix: Originals tab now auto-scans and shows backup stats as soon as the page 
   loads, without requiring a manual Refresh click.

#### 1.0.51

 * New: Original file backup and restore. Before each optimisation (upload and bulk),
   the plugin saves a copy of the source image to elsio-originals/ inside the uploads
   folder. A new Originals tab lets you restore all images to their pre-optimisation
   state or discard the backups to free disk space. Backups are protected from direct
   browser access on Apache and are deleted automatically when an attachment is 
   removed.

#### 1.0.50

 * Security: Path traversal via symlinks — upload directory guard now uses `realpath()`
   to resolve symlinks before comparing paths, preventing a symlink inside uploads
   from targeting files elsewhere on the filesystem. Applies to both bulk optimisation
   and thumbnail regeneration AJAX handlers.
 * Security: `wp_upload_dir()` error return is now checked before accessing `basedir`;
   if the uploads directory cannot be resolved the request is rejected cleanly.
 * Fixed: `filesize()` returns `false` on stat failure; all call sites now check
   for `false` before casting to `int`, preventing silent 0-byte size comparisons
   that could produce wrong PNGJPEG or WebP sidecar decisions.
 * Fixed: `set_error_handler()` in the bulk optimiser is now wrapped in try/finally,
   guaranteeing the handler is restored even if `getimagesize()` throws an exception.

#### 1.0.49

 * Fixed: WebP sidecar was not generated for images that were already within size
   limits and did not need recompression. The early-return path in `optimize()` 
   now generates the sidecar when missing and `generate_webp` is enabled.

#### 1.0.48

 * Fixed: `insert_rules()` in `ELSIO_Htaccess` now aborts when the initial block-
   removal step fails, preventing duplicate marker blocks from being written to `.
   htaccess`.

#### 1.0.47

 * Fixed: WebP rewrite rules were inserted after the WordPress block in .htaccess,
   causing Apache to short-circuit on its „file exists  stop [L]“ rule before ever
   evaluating the WebP conditions. Rules are now always placed before `# BEGIN WordPress`.
   Existing installations that have the block in the wrong position are automatically
   corrected on next settings save or plugin activation.

#### 1.0.46

 * Fixed: `.webp.webp` double extension created when the source file was already
   a WebP (e.g. an uploaded `.webp` image or a WebP thumbnail). `generate_webp_sidecar()`
   now skips WebP sources entirely — the `.htaccess` rewrite rule only covers JPEG/
   PNG requests so a WebP sidecar for a WebP file would never be served anyway.

#### 1.0.45

 * Fixed: Original image was left without a .webp sidecar after running Regenerate
   Thumbnails. `compress_thumbnails_filter` now also generates the main file’s WebP
   sidecar when missing. During normal uploads the existing sidecar is detected 
   and skipped, so no double-processing occurs.

#### 1.0.44

 * Fixed: Thumbnail .webp sidecars were orphaned on disk when an attachment was 
   deleted. `delete_webp_sidecar()` now reads attachment metadata and removes the.
   webp sidecar for every thumbnail size alongside the main file’s sidecar.

#### 1.0.43

 * Fixed: Dead `result.style.display = 'none'` assignment in ghost-scan handler 
   was immediately overridden — removed the redundant line.
 * Fixed: Orphaned JSDoc block that no longer documented any function was removed
   from admin JS.
 * Fixed: File-level docblock in `class-elsio-bulk-optimizer.php` now correctly 
   lists all six AJAX endpoints (was „three“).
 * Fixed: `get_active_tab()` docblock now includes `'regen'` in its return value
   list.

#### 1.0.42

 * Fixed: Thumbnail regeneration no longer fails with „metadata could not be saved“—`
   wp_update_attachment_metadata()` returns false both on DB error and when the 
   stored value is unchanged, so false was treated as success rather than a hard
   error.

#### 1.0.41

 * Improved: `wp_enqueue_script` now uses the WP 6.3+ array form with `strategy:
   defer`, allowing the browser to download the admin script in parallel and execute
   it after DOM parsing — no change to behaviour, better page load performance.
 * Improved: `register_setting` now declares `type: object` for schema completeness
   as recommended since WP 5.5.

#### 1.0.40

 * Added: `uninstall.php` — removes all plugin options and post-meta (`elsio_options`,`
   _elsio_optimised`, `_elsio_thumbs_regen`, `_elsio_file_hash`) when the plugin
   is deleted.

#### 1.0.39

 * Fixed: `require_once` for admin image helpers now loaded after permission check
   in both bulk-optimizer and thumb-regen AJAX handlers.
 * Fixed: `wp_update_attachment_metadata()` return value checked in thumbnail regeneration—
   returns an error instead of silently marking success if the DB write fails.
 * Fixed: All admin buttons now have explicit `type="button"` to prevent accidental
   form submission.
 * Fixed: Added documentation comment in url-replacer noting the `allowed_classes
   => false` limitation for PHP-serialized object properties.

#### 1.0.38

 * Fixed: Critical JavaScript syntax error introduced in 1.0.37 — macOS `sed` wrote
   literal `\n\t` characters instead of real newlines when splitting the timer variable
   declarations, breaking the entire admin script (regen, dedup scan, bulk optimise,
   and ghost cleanup all non-functional).

#### 1.0.37

 * Fixed: Regenerate Thumbnails tab was completely broken — `regenLog()` was called
   but only `regenLogMsg()` was defined, causing a JavaScript runtime error.
 * Fixed: `unserialize()` in `ELSIO_Url_Replacer` now passes `['allowed_classes'
   => false]` to prevent PHP object injection from malicious serialised postmeta
   values.
 * Fixed: Replaced the single shared `pendingTimer` with four separate timers (`
   bulkTimer`, `ghostTimer`, `dedupTimer`, `regenTimer`) so concurrent or back-to-
   back operations can never cancel each other’s inter-image delay.

#### 1.0.36

 * Added: Regenerate Thumbnails tab — bulk-regenerates all thumbnail sizes for existing
   Media Library images, one at a time with progress bar, stop button, and reset
   flags. Useful after changing image sizes in your theme.

#### 1.0.35

 * Fixed: PNGJPEG URL replacement now covers `post_excerpt` and all postmeta values(
   including PHP-serialised data stored by Elementor, ACF, WPBakery, and other page
   builders), not just `post_content`. The new `ELSIO_Url_Replacer` helper is also
   used by the duplicate-finder cleanup.

#### 1.0.34

 * Fixed: Bulk optimiser no longer calls `wp_generate_attachment_metadata()` unconditionally
   on every image. It now only regenerates metadata (and thumbnails) when the format
   changed (PNGJPEG) or the image was resized — i.e. when stored metadata is genuinely
   stale. For pure compression passes, existing thumbnails are compressed in-place
   and metadata is left untouched, preventing valid attachment records from being
   overwritten with potentially incomplete data.
 * Fixed: Thumbnails were previously double-processed during bulk runs — once by`
   compress_thumbnails_filter` (triggered inside `wp_generate_attachment_metadata`)
   and again by the manual loop that always followed. The two code paths are now
   mutually exclusive.

#### 1.0.33

 * Fixed: The „Optimised“ and „Pending“ stat counters on the Bulk Optimise tab now
   update automatically after a run completes or flags are reset. A dedicated `elsio_bulk_get_stats`
   AJAX endpoint was added to return all three counters (total / optimised / pending)
   in one call.

#### 1.0.32

 * Fixed: `png_has_transparency()` now returns `true` (assume transparency, skip
   conversion) when GD cannot load the PNG, instead of `false` — prevents producing
   a broken JPEG from an unreadable image.
 * Fixed: `resize_image()` now returns early when the calculated output dimensions
   round to zero, avoiding a `imagecreatetruecolor(0, 0)` failure on very small 
   source images.
 * Fixed: PNGJPEG URL replacement in the bulk optimiser now fetches matching rows
   and replaces in PHP (`str_replace`) instead of using SQL `REPLACE()`, so only
   exact URL occurrences are updated and surrounding content cannot be corrupted.
 * Fixed: Duplicate file scan now caches the MD5 hash in post meta (keyed on file
   mtime) so repeated scans skip unchanged files — large libraries scan significantly
   faster on subsequent runs.
 * Fixed: `ajax_process_one()` now validates that the attachment file path falls
   within the uploads directory before processing, guarding against third-party 
   filters that could redirect to an unexpected location.
 * Improved: PNG transparency Stage 3 is now split into a fast 20×20 grid sample(
   3a) followed by a full pixel scan (3b). Transparent images with scattered pixels
   exit after the grid; opaque images are still guaranteed correct via the full 
   scan.

#### 1.0.31

 * Fixed: Race condition in WebP sidecar size comparison — `filesize()` calls are
   now guarded with `file_exists()` to prevent PHP warnings if a concurrent process
   removes the file between stat-cache clear and size read.
 * Fixed: `generate_webp_sidecar()` now guards `imagewebp()` with an internal `function_exists()`
   check, making the method safe to call directly without relying on the caller’s
   guard.
 * Fixed: `resize_image()` now returns false immediately when either source dimension
   is zero, preventing a division-by-zero on corrupted image files.
 * Fixed: `png_has_transparency()` now validates the 8-byte PNG signature before
   reading the color-type byte, so a truncated or mis-identified file cannot produce
   a false result.
 * Fixed: Duplicate-finder regex patterns now use `preg_quote()` on the ID string
   for future-proofing, even though `absint()` already guarantees digits only.
 * Improved: Replaced magic literals (`4`, `6`, `0x7F`, `9`, `26`) in `ELSIO_Image_Optimizer`
   with named class constants (`PNG_COLOR_TYPE_GREYSCALE_ALPHA`, `PNG_COLOR_TYPE_RGBA`,`
   GD_ALPHA_BITMASK`, `GD_PNG_MAX_COMPRESSION`, `PNG_HEADER_READ_BYTES`) for clarity.
 * Improved: Informational `error_log` messages (PNGJPEG discarded, WebP sidecar
   discarded) now carry an `[INFO]` tag to distinguish them from actual errors in
   the log.

#### 1.0.30

 * Fixed: `png_has_transparency()` Stage 3 previously sampled a 10×10 pixel grid,
   which could miss a small transparent area. It now scans every pixel so that even
   a single transparent pixel prevents PNGJPEG conversion.

#### 1.0.29

 * Fixed: PNGJPEG conversion broke image links in posts. Two root causes:
    1. `handle_upload_filter()` returned the original `$upload` array unchanged after
       conversion — WordPress created the attachment record with `image/png` MIME type
       and the old `.png` URL even though the file on disk was already a `.jpg`. The
       filter now updates `$upload['file']`, `$upload['url']` and `$upload['type']`
       when conversion happened, so the attachment is registered correctly from the
       start.
    2. Bulk optimizer never updated existing `<img>` references in post content after
       conversion. It now captures the old PNG URL before changing the stored file 
       path, calls `wp_update_post()` to set `post_mime_type` to `image/jpeg`, then
       runs a `REPLACE()` SQL query to rewrite all occurrences of the old URL to the
       new JPEG URL across all post content.

#### 1.0.28

 * Fixed: Palette PNGs (color type 3, e.g. icons) had their transparency silently
   missed by `png_has_transparency()` — `imagecolorat()` returns a palette index
   on non-truecolor images whose high bits are not alpha. The function now calls`
   imagepalettetotruecolor()` before sampling so alpha bits are meaningful.
 * Fixed: Transparent corners (typical for circular/icon PNGs) could theoretically
   be missed by the 10×10 grid if all sampled points fell inside an opaque area.
   The function now explicitly checks all four corners as a dedicated stage before
   the grid scan, guaranteeing corner transparency is always detected.

#### 1.0.27

 * Fixed: `PHP Warning: imagewebp(): Palette image not supported by webp` — palette-
   based PNGs (color type 3, indexed color) loaded by GD are not truecolor and cannot
   be passed to `imagewebp()` or certain `imagepng()` operations. Added an `imageistruecolor()`
   check in `load_image()` immediately after `imagecreatefrompng()`: if the result
   is a palette image, `imagepalettetotruecolor()` is called before returning the
   resource. This also prevents three duplicate warnings (original + thumbnails).

#### 1.0.26

 * Fixed: Pending count in the stats row was not refreshed after ghost attachment
   cleanup completed. Added `refreshPendingCount()` call at the end of the ghost`
   cleanNext()` loop.

#### 1.0.25

 * Fixed: „Fix all duplicates“ had no effect — duplicate attachments were never 
   actually deleted. `new URLSearchParams({ 'dup_ids[]': [1,2,3] })` serialised 
   the array as a single comma-joined string (`dup_ids[]=1%2C2%2C3`), so PHP received
   a string rather than an array, `is_array()` returned false, and the ID list was
   discarded. Replaced the `Object.assign` + `URLSearchParams(object)` pattern in`
   post()` and `postRaw()` with a `buildParams()` helper that iterates array values
   and appends them individually, producing correct `dup_ids[]=1&dup_ids[]=2` serialisation.

#### 1.0.24

 * Fixed: PHPCS warning — replaced `fopen`/`fread`/`fclose` in `png_has_transparency()`
   with `file_get_contents(..., 0, 26)` + `phpcs:ignore` annotation; reads only 
   the 26-byte PNG header without loading the whole file via WP_Filesystem.

#### 1.0.23

 * Fixed: XSS risk in dedup summary — `buildDedupSummaryHTML()` injected backend
   values directly into `.innerHTML`. Replaced with DOM-based `buildDedupSummary()`
   using `textContent` throughout; no user-controlled data can reach the parser.
 * Fixed: `dedupProcessNext()` and `dedupFinish()` accessed `dedupBar`, `dedupProgressWrap`,`
   dedupLabel`, `btnDedupFix`, `btnDedupScan` without null checks — any missing 
   DOM element crashed the entire fix flow. Added guards throughout.
 * Fixed: `onGhostsCleanClick()` called `JSON.parse(btnClean.dataset.ids)` without
   try/catch — malformed data would throw and break the cleanup handler. Wrapped
   in try/catch with an error log message.
 * Fixed: PNGJPEG path detection in bulk optimizer checked `file_exists($jpg_path)`
   alone — a pre-existing .jpg with the same stem would be mistakenly used. Now 
   also verifies the original PNG is gone (`!file_exists($file_path)`) before treating
   the .jpg as the converted output.
 * Fixed: `formatBytes()` did not handle negative or non-numeric input — normalised
   with `Math.max(0, parseInt(...) || 0)`.
 * Fixed: `sprintf()` returned `undefined` for out-of-bounds positional args — added
   bounds check, returns empty string instead.
 * Fixed: Pending `setTimeout` timers were not cancelled on page unload — AJAX requests
   could fire after navigation. Added `beforeunload` listener that clears `pendingTimer`.
 * Fixed: `is_apache()` returned false for Apache servers where `SERVER_SOFTWARE`
   is masked by a proxy. Added `function_exists('apache_get_modules')` as a fallback.
 * Clarified: PNG compression intentionally reuses the JPEG quality setting for 
   GD compression level — added inline comment to make this explicit.

#### 1.0.22

 * Fixed: PNGJPEG conversion block destroyed the GD image resource before falling
   through to step 3 — any PNG that triggered the path (JPEG not smaller, or save
   failed) would attempt to use a freed resource. Restructured to early-return only
   when JPEG is actually kept; `$image` is now destroyed exactly once.
 * Fixed: `png_has_transparency()` only sampled a 10×10 pixel grid, so PNGs with
   an alpha channel (color type 4 or 6) that happened to have all sampled pixels
   fully opaque were incorrectly converted to JPEG. Added a pre-check of the PNG
   color-type header byte (offset 25) — types 4 and 6 now return `true` immediately
   without loading the image.

#### 1.0.21

 * Fixed: Gutenberg block `"id":5` LIKE pattern also matched `"id":15` — replaced
   SQL REPLACE with PHP-side `preg_replace` using a negative-lookahead `(?!\d)` 
   boundary, preventing IDs that start with the same digits from being corrupted.
 * Fixed: Dedup progress bar had class `elsio-progress-bar` instead of `elsio-progress-
   fill` — the animated fill bar was invisible.
 * Fixed: `ajax_process_group()` had no upper bound on `dup_ids[]` — added a hard
   limit of 1000 IDs per request to prevent DoS via oversized payloads.
 * Fixed: PNGJPEG conversion always deleted the source PNG even when the resulting
   JPEG was larger — now compares file sizes and discards the JPEG if it is not 
   smaller, keeping the original PNG.
 * Fixed: WebP sidecar deletion (when sidecar was not smaller than source) was silent—
   now logs a notice under `WP_DEBUG_LOG`.

#### 1.0.20

 * New feature: „Clean Up Ghost Attachments“ section in the Bulk Optimise tab. Scans
   for Media Library records whose files no longer exist on disk, then deletes the
   orphaned DB records one by one with a confirmation step. Files are already missing—
   only the database records are removed.

#### 1.0.19

 * Fixed: Ghost attachments (DB record exists but file missing on disk) were counted
   as errors during bulk optimisation. Now returned as a success with `skipped:true`,
   logged in orange as a warning, and excluded from the error count.

#### 1.0.18

 * Fixed: „Fix all duplicates“ button had no click handler — `initDedup()` ran on
   page load when the Duplicates tab was not active, so all `getElementById()` calls
   returned null. Replaced with document-level event delegation so clicks are captured
   regardless of which tab rendered the page.

#### 1.0.17

 * Fixed: Duplicate finder stat boxes showed `undefined` labels — i18n keys `groups`,`
   redundantFiles`, `recoverable` were missing from the PHP localization array.
 * Fixed: „Scanning Media Library…“ displayed the HTML entity literally — replaced
   with plain ASCII ellipsis since `textContent` does not parse HTML entities.

#### 1.0.16

 * New feature: „Find Duplicates“ tab under Settings  Image Optimiser.
 * Scans the entire Media Library for exact duplicate images using MD5 file hashing.
 * Keeps the oldest copy (lowest attachment ID) and updates all references: image
   URLs in post content, Gutenberg block `id` attributes, `wp-image-X` CSS classes,
   and `_thumbnail_id` featured image meta.
 * Duplicate attachments are then permanently deleted via `wp_delete_attachment()`.
 * Scan uses a 120-second timeout to handle large libraries gracefully.

#### 1.0.15

 * Fixed: WordPress-generated thumbnail sizes (150×150, 300×225, 768×576, 1024×768,
   etc.) were never compressed — only the original file was processed. Added `wp_generate_attachment_metadata`
   filter to compress all thumbnails on upload, and added thumbnail compression 
   loop to the bulk optimiser. Resize and PNGJPEG conversion are intentionally disabled
   for thumbnails to preserve WordPress filename expectations.

#### 1.0.14

 * Fixed: PHP 8.1 deprecation notice „Implicit conversion from float to int loses
   precision“ on `imagecolorat()` in `png_has_transparency()`. Operator precedence
   caused `$step` to remain a float (`(int)` was only applied to `min()`, not to
   the division result). Fixed by wrapping the full expression: `(int) round( min(
   $w, $h ) / 10 )`.

#### 1.0.13

 * Fixed: Bulk optimiser did not update WordPress attachment metadata after resizing.
   The Media Library was still showing original dimensions from the database even
   though the file on disk had been resized. Now calls `wp_generate_attachment_metadata()`
   and `wp_update_attachment_metadata()` after each optimisation.
 * Fixed: PNGJPEG conversion during bulk optimise now correctly updates the stored
   file path via `update_attached_file()`.

#### 1.0.12

 * Fixed: PNG images within the configured max dimensions were silently skipped 
   and never compressed. `needs_recompression()` now includes `image/png` so PNG
   files are always re-encoded regardless of their dimensions.

#### 1.0.11

 * Fixed: HTML entity `&#8212;` displayed as literal text in the bulk log (e.g. `
   saved &#8212; 74%`). The `log()` function uses `textContent` which does not parse
   HTML entities — replaced the entity with the actual UTF-8 em dash character `—`
   in the PHP string.

#### 1.0.10

 * Fixed: Double percent sign (`%%`) displayed in bulk optimisation log and progress
   counter. The PHP `%%` escape (for PHP sprintf) was incorrectly used in strings
   passed to the JavaScript sprintf — replaced with a single literal `%`.

#### 1.0.9

 * Fixed: Added `@package` tag to main plugin file doc block to satisfy PHPCS file
   comment requirements.
 * Fixed: Added `phpcs:ignore Generic.PHP.DeprecatedFunctions.Deprecated` on all`
   imagedestroy()` calls — function remains callable in PHP 8 and is required for
   PHP 7.4 compatibility.
 * Fixed: Added `phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler`
   on `set_error_handler()` calls used to suppress GD warnings without the `@` operator.
 * Fixed: Corrected doc comment long descriptions in `class-elsio-htaccess.php` 
   that started with lowercase (PHPCS capitalization rule).
 * Fixed: Added loop incrementer `phpcs:ignore` annotation on the pixel-sampling
   loop in `png_has_transparency()`.

#### 1.0.8

 * Fixed: WordPress.Security.EscapeOutput.OutputNotEscaped on $notice_text — store
   raw translated string with __() and escape at the point of output with esc_html().

#### 1.0.7

 * Fixed: WordPress.WP.I18n.MissingTranslatorsComment — extracted all __() and _n()
   calls that contain placeholders into standalone variables so the /* translators:*/
   comment sits on the line immediately above the i18n function call, satisfying
   WPCS token-level validation.

#### 1.0.6

 * i18n: Fixed `\uXXXX` JS escape sequences used inside PHP strings — replaced with
   HTML entities (`&#8230;`, `&#8212;`, `&#8220;`, `&#8221;`).
 * i18n: Switched multi-placeholder strings to positional format (`%1$s`, `%2$s`…)
   so translators can reorder arguments.
 * i18n: Added `/* translators: */` comments to all strings containing placeholders.
 * i18n: Updated JS `sprintf()` to support both sequential (`%s`) and positional(`%
   1$s`) token formats.
 * i18n: Created `languages/effortless-simple-image-optimiser.pot` with all 60+ 
   translatable strings.

#### 1.0.5

 * Fixed: PNG compression level formula was inverted — quality 82 now correctly 
   maps to GD level 7 instead of level 2.
 * Fixed: `imagewebp()` return value now checked; failures are logged under WP_DEBUG_LOG.
 * Fixed: WebP sidecar is now deleted if it is not smaller than the source file,
   preventing .htaccess from serving a larger WebP.
 * Fixed: Bulk optimizer now resolves the correct output path when PNG is converted
   to JPEG, preventing false 100% saving reports.
 * Fixed: Added `delete_attachment` hook — `.webp` sidecar files are now removed
   when the parent image is deleted from the Media Library.
 * Fixed: AJAX `fetch()` requests in JS now carry a 60-second `AbortController` 
   timeout to prevent the bulk queue hanging indefinitely.

#### 1.0.4

 * PHP/WordPress/PHPCS/WPCS compliance pass across all files.
 * Replaced `@` error suppression with `set_error_handler`/`restore_error_handler`.
 * `error_log()` calls are now guarded by `WP_DEBUG_LOG`.
 * `unlink()` replaced with `wp_delete_file()`.
 * `file_get_contents()` replaced with WP_Filesystem in htaccess class.
 * `is_writable()` replaced with `wp_is_writable()`.
 * `insert_with_markers()` and `get_home_path()` dependencies loaded explicitly.
 * `$_SERVER['SERVER_SOFTWARE']` sanitised with `sanitize_text_field()` + `wp_unslash()`.
 * All `$_POST` inputs sanitised with `absint()` + `wp_unslash()`.
 * `$_GET` tab/action values sanitised with `sanitize_key()` + `wp_unslash()`.
 * Inline `oninput` JS removed from range fields; replaced with `data-linked` attributes
   handled in JS.
 * `printf` with raw HTML replaced with proper `wp_kses()` escaping via `render_env_row()`
   helper.
 * `echo $notice` replaced with pre-escaped output split into typed variables.
 * `$wpdb->delete()` direct query replaced with `delete_metadata( 'post', 0, $key,'',
   true )`.
 * `new WP_Query()->found_posts` replaced with `get_posts()` + `count()` and `no_found_rows
   => true`.
 * Added `return` statements after `wp_send_json_error()` calls to make flow explicit.
 * Added `label_for` to all settings fields for accessible form labels.
 * IIFE closure in JS uses `}()` form; `finally` chain preserved for modern browsers.

#### 1.0.3

 * Added Apache `.htaccess` WebP delivery via mod_rewrite (Option 1).
 * Rules inserted automatically on activation, removed on deactivation, re-synced
   on settings save.
 * `Vary: Accept` header appended so CDNs cache JPEG and WebP variants separately.
 * Environment sidebar now shows Apache detection, `.htaccess` writability, and 
   rewrite rule status.
 * „Insert now“ button to manually inject rules if they are missing post-activation.

#### 1.0.2

 * Added Bulk Optimise tab under Settings  Image Optimiser.
 * New AJAX endpoints: `elsio_bulk_get_ids`, `elsio_bulk_process_one`, `elsio_bulk_reset_flags`.
 * Progress bar, live log and stats panel for bulk runs.
 * Post-meta flag `_elsio_optimised` prevents reprocessing already-optimised images.
 * „Re-optimise all“ checkbox and „Reset flags“ button for manual re-runs.

#### 1.0.1

 * Added readme.txt with full documentation.
 * Minor version bump following project conventions.

#### 1.0.0

 * Initial release.
 * JPEG compression with configurable quality.
 * PNG compression and optional PNG  JPEG conversion (transparency-aware).
 * Image resizing with aspect-ratio preservation.
 * Optional WebP sidecar generation.
 * Admin settings page under Settings  Image Optimiser.
 * GD availability check with graceful fallback.

## Meta

 *  Verze **1.0.56**
 *  Poslední aktualizace **před 1 týdnem**
 *  Aktivních instalací **Méně než 10**
 *  Verze WordPressu ** 5.9 nebo novější **
 *  Testováno až do WordPressu **6.9.4**
 *  Verze PHP ** 7.4 nebo novější **
 *  Jazyk
 * [English (US)](https://wordpress.org/plugins/effortless-simple-image-optimiser/)
 * Štítky
 * [compress images](https://cs.wordpress.org/plugins/tags/compress-images/)[image optimisation](https://cs.wordpress.org/plugins/tags/image-optimisation/)
   [resize images](https://cs.wordpress.org/plugins/tags/resize-images/)[webp](https://cs.wordpress.org/plugins/tags/webp/)
 *  [Podrobnosti](https://cs.wordpress.org/plugins/effortless-simple-image-optimiser/advanced/)

## Hodnocení

Zatím nebyly zadány žádné recenze.

[Přidat moje hodnocení](https://wordpress.org/support/plugin/effortless-simple-image-optimiser/reviews/#new-post)

[Zobrazit všechny recenze](https://wordpress.org/support/plugin/effortless-simple-image-optimiser/reviews/)

## Spolupracovníci

 *   [ domclic ](https://profiles.wordpress.org/domclic/)

## Podpora

Potřebujete pomoc?

 [Fórum podpory](https://wordpress.org/support/plugin/effortless-simple-image-optimiser/)