{"id":357215,"date":"2026-08-28T17:50:49","date_gmt":"2026-08-28T17:50:49","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/webp-image-fetcher-compressor\/"},"modified":"2026-08-28T17:50:34","modified_gmt":"2026-08-28T17:50:34","slug":"pixelcinch-image-optimizer","status":"publish","type":"plugin","link":"https:\/\/it.wordpress.org\/plugins\/pixelcinch-image-optimizer\/","author":23532986,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"2.6.2","stable_tag":"2.6.2","tested":"7.1","requires":"5.6","requires_php":"7.4","requires_plugins":null,"header_name":"Pixelcinch Image Optimizer","header_author":"Tayyab","header_description":"Converts your Media Library images to compressed WebP, with a 100KB-per-image target, automatic recompression, and safe cleanup of the original files once you're ready.","assets_banners_color":"","last_updated":"2026-08-28 17:50:34","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/tayyabatta.com\/portfolio\/pixelcinch-image-optimizer","header_author_uri":"https:\/\/tayyabatta.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":75,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","changelog"],"tags":{"2.6.2":{"tag":"2.6.2","author":"tayyabatta","date":"2026-08-28 17:50:34","revision":3670762}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-256x256.png":{"filename":"icon-256x256.png","revision":3670785,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["2.6.2"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[262246],"plugin_tags":[],"plugin_category":[],"plugin_contributors":[],"plugin_business_model":[],"class_list":["post-357215","plugin","type-plugin","status-publish","hentry","plugin_section-dashboard-widgets","plugin_committers-tayyabatta"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/pixelcinch-image-optimizer\/assets\/icon-256x256.png?rev=3670785","icon_2x":"https:\/\/ps.w.org\/pixelcinch-image-optimizer\/assets\/icon-256x256.png?rev=3670785","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Converts images to WebP and compresses each one toward a 100KB target:<\/p>\n\n<ol>\n<li>Media Library optimizer - scans existing attachments (JPG\/PNG\/GIF,\nplus optional WebP\/SVG\/RAW support) and converts them to WebP in\nsmall batches, avoiding PHP timeouts.<\/li>\n<li>Manage WebP images - review any WebP image in your library, compress\nindividual ones further, and choose exactly which original files to\npermanently delete once you're happy with the result.<\/li>\n<\/ol>\n\n<h3>Compression modes<\/h3>\n\n<p>Choose one mode; it applies wherever conversion happens:<\/p>\n\n<ul>\n<li>Less Compress (quality mode): starts at WebP quality 90, only steps\ndown to a floor of quality 70, and never resizes the image. If a\ndetailed image can't get under 100KB without going below that quality\nfloor, it is left larger rather than degraded further.<\/li>\n<li>High Compress (aggressive mode): starts at quality 78, steps down to\na floor of quality 20, and if still too big, shrinks dimensions by\n20% at a time down to a 120px floor - forcing the result under 100KB\n\"at any price.\"<\/li>\n<\/ul>\n\n<h3>Requirements<\/h3>\n\n<ul>\n<li>Imagick PHP extension with WebP support (preferred), or<\/li>\n<li>GD PHP extension with WebP support (imagewebp())<\/li>\n<\/ul>\n\n<h3>Security notes<\/h3>\n\n<ul>\n<li>All admin actions require the <code>manage_options<\/code> capability and a\nverified nonce.<\/li>\n<li>Every file this plugin processes is validated as a real image via\ngetimagesize() + fileinfo mime detection (or, for SVG, a dedicated\ncontent-safety scan), not by trusting its extension.<\/li>\n<li>Filenames are sanitized and destination paths are checked to stay\ninside wp-content\/uploads before any file is written.<\/li>\n<li>All AJAX output is via wp_send_json_success\/error; all admin UI output\nis escaped (esc_html\/esc_attr\/esc_url).<\/li>\n<\/ul>\n\n<p>The Media Library optimizer keeps your original files on disk; it only\nrepoints the attachment's registered file to the new .webp version, so\nyou can restore from the original if needed - until you use the new\n\"Delete original files\" tool below (see 1.2.0).<\/p>\n\n<h3>For Developers<\/h3>\n\n<p>Extension points other plugins can hook into - none of these change\ndefault behavior on their own, they're no-ops until something uses them:<\/p>\n\n<ul>\n<li><code>pixelcinch_after_convert<\/code> (action) - fires after an attachment is\nconverted, with the attachment ID and a result summary array.<\/li>\n<li><code>pixelcinch_after_delete_original<\/code> (action) - fires after an original\n(pre-WebP) file is actually deleted from disk.<\/li>\n<li><code>pixelcinch_compression_profile<\/code> (filter) - the quality\/resize tuning\nvalues used for a given compression mode.<\/li>\n<li><code>pixelcinch_scannable_mime_types<\/code> (filter) - the list of MIME types\noffered as scan\/convert source formats.<\/li>\n<li><code>pixelcinch_default_settings<\/code> (filter) - the default settings array.<\/li>\n<li><code>pixelcinch_sanitize_settings<\/code> (filter) - the sanitized settings array\nright before it's stored; add your own keys here alongside your own\nentries in <code>pixelcinch_default_settings<\/code>.<\/li>\n<\/ul>\n\n<!--section=changelog-->\n<h4>2.6.2<\/h4>\n\n<ul>\n<li>Compliance: removed the custom AJAX output-buffering mechanism entirely.\nIt previously opened an output buffer in one method and closed it from\na separate 'shutdown'-hooked method, which left buffer ownership\ndependent on hook execution order rather than a single function scope.\nThe plugin no longer performs any output buffering.<\/li>\n<\/ul>\n\n<h4>2.6.1<\/h4>\n\n<ul>\n<li>Compliance: the AJAX output buffer opened to strip stray PHP\nwarnings\/notices from JSON responses is now explicitly closed via\nob_get_clean() on 'shutdown', rather than left open for PHP's implicit\nend-of-request flush.<\/li>\n<\/ul>\n\n<h4>2.6.0<\/h4>\n\n<ul>\n<li>Renamed to \"Pixelcinch Image Optimizer\" (slug: pixelcinch-image-optimizer).\nDisplay name, text domain, admin page slugs, and internal references\nupdated throughout. No functional changes.<\/li>\n<\/ul>\n\n<h4>2.5.1<\/h4>\n\n<ul>\n<li>Ran the plugin through PHP_CodeSniffer with the WordPress Coding\nStandards ruleset and cleaned up everything it flagged: statement\nalignment, increment style, an array-formatting spot, an unused\nfilter-callback parameter, and a reserved-keyword parameter name.\nNo behavior changes.<\/li>\n<\/ul>\n\n<h4>2.5.0<\/h4>\n\n<ul>\n<li>Added six action\/filter hooks (see \"For Developers\" above) so other\ncode can extend conversion, deletion, compression tuning, supported\nformats, and settings without modifying this plugin's files. Purely\nadditive - no existing behavior changes.<\/li>\n<\/ul>\n\n<h4>2.4.3<\/h4>\n\n<ul>\n<li>Compliance: replaced an <code>ini_set( 'display_errors', ... )<\/code> call used to\nkeep stray PHP notices out of our AJAX JSON responses with output\nbuffering instead, since plugins altering that php.ini directive at\nruntime is flagged by Plugin Check. No behavior changes.<\/li>\n<\/ul>\n\n<h4>2.4.2<\/h4>\n\n<ul>\n<li>Compliance: bumped \"Tested up to\" to 7.1.<\/li>\n<li>Compliance: prefixed the two variables in uninstall.php that Plugin\nCheck flagged as unprefixed globals. No behavior changes.<\/li>\n<\/ul>\n\n<h4>2.4.1<\/h4>\n\n<ul>\n<li>Renamed the plugin to \"Pixelcinch Image Optimizer\" (previously \"WebP\nImage Fetcher &amp; Compressor\"), per WordPress.org naming guidelines -\ndescriptive of what the plugin actually does (compress images) with a\ndistinct identifier at the front instead of leading with \"WebP\".<\/li>\n<li>Compliance: the dashboard widget's inline <code>&lt;style&gt;<\/code> block is now\nenqueued properly via wp_enqueue_style() instead.<\/li>\n<li>Compliance: every function\/class\/constant\/option\/hook prefix changed\nfrom <code>iwc<\/code>\/<code>IWC<\/code> to a prefix derived from the new name, to go with the\nrename above. No behavior changes.<\/li>\n<\/ul>\n\n<h4>2.4.0<\/h4>\n\n<ul>\n<li>Removed: the \"Fetch images from a URL\" tool, which scanned a given\npage for image sources and downloaded them. The WordPress.org Plugin\nDirectory review team classified this as scraping functionality,\nwhich isn't permitted regardless of the safeguards that were in place\n(SSRF protections, same-image validation, an explicit on-screen notice\nto only use it on sites you own\/have permission for, etc.) \u2014 the\ncapability itself is what's restricted, not the intent behind it. This\nplugin now only ever processes images already in your own Media\nLibrary, or new uploads made through WordPress's normal upload flow.<\/li>\n<li>The \"Manage WebP images\" step is renumbered to step 2 accordingly.\nNo other functionality changed.<\/li>\n<\/ul>\n\n<h4>2.3.0<\/h4>\n\n<ul>\n<li>New: additional source formats for conversion, each opt-in via checkbox\non the Tools page or Settings:\n\n<ul>\n<li>WebP: recompresses an already-WebP image in place using the full\nquality\/resize search (not just the single-shot \"compress further\"\nslider), useful for a one-time pass over WebP files that arrived\nfrom somewhere other than this plugin.<\/li>\n<li>SVG: rasterized to WebP via ImageMagick, only when the server's\nImageMagick build actually has SVG support (most shared hosting\ndoes not \u2014 the checkbox is disabled with a clear note when\nunavailable). Every SVG is scanned before processing and rejected\nif it contains scripts, event handler attributes, XML external\nentity declarations, or references to external URLs \u2014 the class of\ncontent that makes ImageMagick+SVG a known security risk\n(\"ImageTragick\"). Rendering also runs under tight ImageMagick\nresource limits (memory\/width\/height\/time) so a pathological file\nfails safely instead of exhausting server resources.<\/li>\n<li>RAW camera files (CR2, CRW, NEF, NRW, ARW, RAF, ORF, RW2, PEF, SRW,\nDNG): converted via ImageMagick, only when the server's build\nsupports that specific format. Automatically picks the\nhighest-resolution embedded frame (RAW files often bundle a\nthumbnail and preview alongside the full frame).<\/li>\n<\/ul><\/li>\n<li>New: optional \"Allow SVG\/RAW uploads\" setting (off by default) so\nthese file types can actually be uploaded through the Media Library\nat all \u2014 WordPress blocks them otherwise. The same SVG safety scan\nruns at upload time, before a file is ever written to disk, not just\nwhen converting it later.<\/li>\n<li>Fix: the image-conversion loop is now wrapped in try\/catch for every\nsource type (previously only some paths were) \u2014 an unexpected\nmid-conversion failure always returns a clean error now instead of\nrisking an uncaught exception.<\/li>\n<li>The \"unsupported format\" case (e.g. an SVG\/RAW file on a server\nwithout the right ImageMagick support) is tracked distinctly so the\nscanner doesn't keep retrying it, and is reflected in the Tools page\nlibrary overview.<\/li>\n<\/ul>\n\n<h4>2.2.2<\/h4>\n\n<ul>\n<li>Compliance: resolved 6 remaining Plugin Check warnings in\nclass-pixelcinch-local.php (WordPress.Security.ValidatedSanitizedInput.InputNotSanitized).\nA recognized sanitizer (absint()\/sanitize_text_field()) is now applied\ndirectly at every $_POST read, rather than only inside this plugin's\nown whitelist helper methods a few lines later - the previous version\nwas already safe (the helpers do whitelist\/absint everything), but\nstatic analysis couldn't see past the function call boundary. No\nbehavior changes.<\/li>\n<\/ul>\n\n<h4>2.2.1<\/h4>\n\n<ul>\n<li>Compliance: addressed every item from a WordPress.org Plugin Check\nscan - added the required License\/License URI header and a LICENSE.txt\nfile, updated readme.txt's \"Tested up to\" and added the missing Short\nDescription, replaced a raw is_writable() call with WordPress's\nwp_is_writable() wrapper in uninstall.php, added a missing translators\ncomment for a string with a placeholder, and annotated every direct\ndatabase call and nonce-verified-via-shared-helper AJAX input with the\nspecific reasoning (no WP_Query equivalent exists, cache is invalidated\nimmediately after, or the nonce check already happened one line above\nvia PIXELCINCH_Security::assert_request() - which static analysis can't trace\ninto on its own). No behavior changes.<\/li>\n<\/ul>\n\n<h4>2.2.0<\/h4>\n\n<ul>\n<li>Change: \"Manage WebP images\" (step 3) now detects every WebP image in\nyour library over 100KB - not just ones this plugin converted. Images\nuploaded as WebP directly, or produced by something else (a\nhosting-level optimizer, another plugin), now show up too and can be\ncompressed further the same way. Untracked images that are already\nunder 100KB are simply left alone, same as before.<\/li>\n<li>Deleting an original only applies to images this plugin converted\n(there's a file to delete); for untracked WebP images there's nothing\nto delete since the WebP file is the only copy - the row clearly notes\nthis and you can still compress it further.<\/li>\n<\/ul>\n\n<h4>2.1.0<\/h4>\n\n<ul>\n<li>Change: split the single admin page into three - Tools (day-to-day\nscan\/convert\/manage actions), Features (integrations like automatic\nWebP serving and Media Library detection), and Settings (persisted\ndefaults) - with tabs to move between them.<\/li>\n<li>New: \"Your Media Library right now\" overview on the Tools page, showing\nreal counts of images pending conversion, already converted by this\nplugin, and already WebP but not tracked by this plugin (e.g. uploaded\nas WebP directly, or optimized automatically by some hosts). Clears up\nthe confusing case where \"Scan &amp; Convert\" reports nothing to do while\nthe manage list also shows nothing - usually it just means there's\nnothing outside what's already covered.<\/li>\n<li>Fix: the \"Install to uploads\/.htaccess\" button was refusing to run on\nany server that didn't literally identify itself as \"Apache\" - which\nwrongly blocked LiteSpeed (used by many shared hosts, including\nHostinger), even though LiteSpeed reads .htaccess the same way Apache\ndoes. It now only blocks on Nginx, which is the one case where\n.htaccess genuinely has no effect.<\/li>\n<\/ul>\n\n<h4>2.0.0<\/h4>\n\n<ul>\n<li>New: Settings page (right on the main screen) to set your defaults \u2014\ndefault compression mode, default scan filters, auto-convert-on-upload,\nbackground conversion, and auto-purge \u2014 so you don't have to reconfigure\nevery run.<\/li>\n<li>New: convert new uploads automatically as soon as they're added to the\nMedia Library (optional, off by default), respecting your saved\nfile-type\/size filters and any excluded images.<\/li>\n<li>New: \"Convert to WebP\" \/ \"Exclude from WebP conversion\" row actions and\nbulk actions right in the normal Media Library screen (Media &gt; Library),\nso you don't have to leave that screen.<\/li>\n<li>New: exclude specific images permanently from every scan, auto-convert,\nand the background job, from the Media Library row action.<\/li>\n<li>New: automatic WebP-serving rules for images this plugin didn't convert\ndirectly (theme assets, hardcoded template images) \u2014 an Apache\ninstaller that only ever writes to wp-content\/uploads\/.htaccess (never\nyour site's main .htaccess), plus a copyable Nginx snippet.<\/li>\n<li>New: detects common offload\/CDN plugins (WP Offload Media, WP-Stateless,\netc.) and warns that local file operations may not match what's\nactually served, since this plugin only reads\/writes local disk.<\/li>\n<li>New: optional auto-purge \u2014 automatically delete original files N days\nafter conversion, instead of relying on remembering to clean up\nmanually. Off by default.<\/li>\n<li>New: optional background conversion via WP-Cron \u2014 processes a small\nbatch of pending images every 5 minutes so a large library finishes\nconverting without needing the browser tab open. Off by default.<\/li>\n<li>New: dashboard widget showing images converted, space saved, images\nstill over 100KB, and originals still awaiting review.<\/li>\n<li>Security: centralized error logging. Real error detail (which can\ninclude server file paths, e.g. from Imagick exceptions) now only ever\ngoes to the server's own debug log when WP_DEBUG_LOG is enabled - AJAX\nresponses only ever contain short, generic messages. Also suppresses\nPHP error\/warning display specifically during this plugin's AJAX\nrequests as defense in depth, and wraps every risky operation\n(compression, batch conversion, deletion) in try\/catch so an unexpected\nfailure can't leak internals to the browser.<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>New: scan filters on the Media Library optimizer. Choose which file\ntypes to include (JPG\/PNG\/GIF, individually), and optionally set a\nminimum file size so only images at or above that size are scanned -\ne.g. \"only images over 100KB\" - leaving smaller, already-lean images\nuntouched. Unchecking the size filter scans images of every size, and\nchecking every file type scans everything, so both \"scan all\" and\nnarrower runs use the same controls.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>New: converting an image now automatically rewrites any existing pages\nor posts that link to the old file, pointing them at the new WebP file\ninstead. This is a direct content rewrite - no redirects are created.\nIt covers the full-size image and every registered thumbnail size, and\nruns again as a safety check right before an original file is deleted\n(useful for images converted by an older version of the plugin).<\/li>\n<li>New: \"Manage converted images\" replaces the old all-or-nothing delete\ntool. It lists your converted images (by default only the ones still\nover 100KB), and lets you tick just the ones you want and delete only\ntheir originals - not the whole library at once.<\/li>\n<li>New: per-image \"Compress further\" control. Pick a quality level with\nthe slider and re-encode that single image on demand, without waiting\nfor a full library re-scan. Uses the original file as the source when\nit's still available for a cleaner result, and keeps the image at its\ncurrent dimensions so it doesn't jump back up to full resolution.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Fix: the settings page is now registered as its own top-level \"WebP\nFetcher\" menu item, so it's easy to find in wp-admin instead of only\nappearing as a submenu under Media.<\/li>\n<li>Fix: the admin page now always appears, even on servers missing\nImagick\/GD WebP support. Previously the whole menu item silently\ndisappeared in that case; now the page loads and clearly explains\nthe missing requirement, with the tools disabled until it's resolved.<\/li>\n<li>New: \"Delete original files\" tool. After converting your Media\nLibrary to WebP, once you've reviewed the results and are sure, you\ncan permanently delete the leftover original JPG\/PNG\/GIF files to\nreclaim disk space. This requires ticking a confirmation checkbox\nplus a browser confirmation dialog, and only ever deletes files this\nplugin itself converted and recorded - never anything else.<\/li>\n<\/ul>","raw_excerpt":"Converts your Media Library images to compressed WebP, targeting roughly 100KB per image.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/357215","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=357215"}],"author":[{"embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/tayyabatta"}],"wp:attachment":[{"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=357215"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=357215"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=357215"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=357215"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=357215"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/it.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=357215"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}