{"id":335661,"date":"2026-07-27T07:48:48","date_gmt":"2026-07-27T07:48:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/bender\/"},"modified":"2026-08-07T08:37:35","modified_gmt":"2026-08-07T08:37:35","slug":"bender-mosaic-image-protection","status":"publish","type":"plugin","link":"https:\/\/fa.wordpress.org\/plugins\/bender-mosaic-image-protection\/","author":23527317,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.1.9","stable_tag":"0.1.9","tested":"7.0.3","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"Bender - Mosaic Image Protection","header_author":"OpenCluster","header_description":"Protezione del diritto d'autore per le immagini: rendering \"a mosaico\" anti-scraping, watermark visibile, metadati di paternit\u00e0 IPTC.","assets_banners_color":"3296e0","last_updated":"2026-08-07 08:37:35","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"","rating":0,"author_block_rating":0,"active_installs":0,"downloads":251,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.1.2":{"tag":"0.1.2","author":"opencluster","date":"2026-07-27 07:48:13"},"0.1.3":{"tag":"0.1.3","author":"opencluster","date":"2026-07-27 09:32:41"},"0.1.4":{"tag":"0.1.4","author":"opencluster","date":"2026-07-27 09:55:20"},"0.1.5":{"tag":"0.1.5","author":"opencluster","date":"2026-07-27 10:34:28"},"0.1.6":{"tag":"0.1.6","author":"opencluster","date":"2026-07-29 09:42:57"},"0.1.7":{"tag":"0.1.7","author":"opencluster","date":"2026-07-31 09:10:05"},"0.1.8":{"tag":"0.1.8","author":"opencluster","date":"2026-08-03 08:53:10"},"0.1.9":{"tag":"0.1.9","author":"opencluster","date":"2026-08-07 08:37:35"}},"upgrade_notice":{"0.1.9":"<p>Protected images now keep the size the theme gave them, and lazy loaders can no longer put the original image URL back on scroll.<\/p>","0.1.6":"<p>Custom themes\/page builders that print images outside the_content()\/the_post_thumbnail() are now protected too \u2014 previously those stayed unprotected silently.<\/p>","0.1.5":"<p>Bugfix: 3 strings weren&#039;t picking up their bundled translation due to an apostrophe mismatch \u2014 now fixed.<\/p>","0.1.4":"<p>Adds bundled translations (IT, ES, FR, DE, PT-BR, ZH-CN) \u2014 no functional change for English-language sites.<\/p>","0.1.3":"<p>Admin UI strings are now translatable (were hardcoded Italian) \u2014 no functional change.<\/p>","0.1.2":"<p>Fixed-value features are now implemented without generic\/parameterized code paths, per Plugin Review feedback.<\/p>","0.1.1":"<p>Unique naming prefix and removal of dormant Pro-only code, per Plugin Review feedback.<\/p>","0.1.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3624274,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3624274,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3624284,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3624284,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.1.2","0.1.3","0.1.4","0.1.5","0.1.6","0.1.7","0.1.8","0.1.9"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3624274,"resolution":"1","location":"assets","locale":"","width":1280,"height":800},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3624274,"resolution":"2","location":"assets","locale":"","width":1280,"height":800}},"screenshots":{"1":"Settings page with protection stats.","2":"Media Library with the \"Protection\" column and bulk actions."}},"plugin_section":[],"plugin_tags":[55129,2972,19833,4096,3241],"plugin_category":[],"plugin_contributors":[273428],"plugin_business_model":[],"class_list":["post-335661","plugin","type-plugin","status-publish","hentry","plugin_tags-anti-scraping","plugin_tags-copyright","plugin_tags-image-protection","plugin_tags-iptc","plugin_tags-watermark","plugin_contributors-opencluster","plugin_committers-opencluster"],"banners":{"banner":"https:\/\/ps.w.org\/bender-mosaic-image-protection\/assets\/banner-772x250.png?rev=3624284","banner_2x":"https:\/\/ps.w.org\/bender-mosaic-image-protection\/assets\/banner-1544x500.png?rev=3624284","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/bender-mosaic-image-protection\/assets\/icon-128x128.png?rev=3624274","icon_2x":"https:\/\/ps.w.org\/bender-mosaic-image-protection\/assets\/icon-256x256.png?rev=3624274","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/bender-mosaic-image-protection\/assets\/screenshot-1.png?rev=3624274","caption":"Settings page with protection stats."},{"src":"https:\/\/ps.w.org\/bender-mosaic-image-protection\/assets\/screenshot-2.png?rev=3624274","caption":"Media Library with the \"Protection\" column and bulk actions."}],"raw_content":"<!--section=description-->\n<p>Your WordPress images travel as a mosaic. Whoever steals them finds only shuffled tiles.<\/p>\n\n<p>Bender protects your site's photos from scrapers, AI training bots, and outright theft, without touching SEO, speed, or the experience of your human visitors.<\/p>\n\n<h4>How it works<\/h4>\n\n<p>On upload (or from the Media Library), Bender automatically generates two derivatives for every image:<\/p>\n\n<ol>\n<li><strong>Mosaic atlas<\/strong> \u2013 the image in full resolution, with an N\u00d7N grid permuted and flipped via HMAC-SHA256 \u2192 Fisher-Yates using a per-image secret key. A single CDN-cacheable file: downloaded as-is, it's an unreadable puzzle.<\/li>\n<li><strong>Signed low-res<\/strong> \u2013 a reduced version with a visible diagonal watermark and IPTC copyright metadata (read by Google Images), used as the <code>&lt;img&gt;<\/code> source: SEO, social previews, and the no-JavaScript fallback.<\/li>\n<\/ol>\n\n<p>The original hi-res URL never appears in the page markup. In the browser, Bender waits for the image to enter the viewport, downloads the atlas, requests the reconstruction map from a REST endpoint protected by a time-limited HMAC token, and reassembles the mosaic on a <code>&lt;canvas&gt;<\/code> with a blur-up cross-fade.<\/p>\n\n<h4>What it blocks (and what it honestly doesn't)<\/h4>\n\n<ul>\n<li>HTML scrapers \/ mass bots \u2014 blocked: the HTML only contains the watermarked low-res<\/li>\n<li>Right-click \"Save image\" \u2014 blocked: the canvas isn't a file<\/li>\n<li>Hi-res hotlinking \u2014 blocked: no plain hi-res URL exists<\/li>\n<li>Downloading the atlas \u2014 useless: permuted, flipped tiles, no map<\/li>\n<li>Map enumeration via REST \u2014 mitigated: time-limited HMAC token, per-IP rate limiting<\/li>\n<li>Screenshots \u2014 not blockable, by any technology<\/li>\n<\/ul>\n\n<p>That's why Bender always signs, not just hides: visible watermarking and IPTC metadata make authorship provable even when a copy slips through.<\/p>\n\n<h4>What's included<\/h4>\n\n<p>This plugin is fully functional as-is, with no locked or restricted features:<\/p>\n\n<ul>\n<li>Automatic protection on upload, unlimited images<\/li>\n<li>6\u00d76 mosaic grid<\/li>\n<li>Visible \"Bender\u2122\" watermark<\/li>\n<li>Default IPTC copyright metadata<\/li>\n<li>JPEG atlas format<\/li>\n<li>Bulk protect\/unprotect from the Media Library<\/li>\n<\/ul>\n\n<p>Denser grids, WebP\/PNG atlas formats, fully customizable watermark and IPTC text, invisible forensic (LSB) watermarking, and configurable token validity are available in <strong>Bender Pro<\/strong>, a separate plugin distributed outside WordPress.org.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>bender-mosaic-image-protection<\/code> folder to <code>\/wp-content\/plugins\/<\/code>, or install directly from the Plugins screen.<\/li>\n<li>Activate the plugin.<\/li>\n<li>Requires PHP 7.4+ with the GD extension (standard on virtually any WordPress hosting).<\/li>\n<li>Go to the <strong>Bender<\/strong> menu to adjust served resolution, quality, and watermark\/IPTC toggles. New uploads are protected automatically by default.<\/li>\n<li>For existing images: Media Library \u2192 select images \u2192 <strong>\"Protect with Bender\"<\/strong> bulk action.<\/li>\n<\/ol>\n\n<p><strong>Page caching<\/strong>: align the token validity (24 hours by default) with your page cache duration, so tokens served from cache remain valid.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"what%20is%20bender%20and%20what%20does%20it%20do%3F\"><h3>What is Bender and what does it do?<\/h3><\/dt>\n<dd><p>Bender is a WordPress plugin that protects images from theft: it breaks them into an unreadable mosaic for scrapers and bots, shows visitors a live canvas reconstruction, and serves search engines a signed low-res version with a watermark and IPTC copyright metadata.<\/p><\/dd>\n<dt id=\"does%20bender%20really%20block%20downloads%20of%20the%20high-resolution%20images%3F\"><h3>Does Bender really block downloads of the high-resolution images?<\/h3><\/dt>\n<dd><p>It blocks automated scrapers, hotlinking, and right-click \"Save image\", because the HTML never contains a plain hi-res URL. It cannot prevent a screenshot, because no web technology can \u2014 that's why every image is still signed with a watermark and IPTC metadata.<\/p><\/dd>\n<dt id=\"does%20bender%20slow%20down%20the%20site%20or%20hurt%20seo%3F\"><h3>Does Bender slow down the site or hurt SEO?<\/h3><\/dt>\n<dd><p>No \u2014 SEO stays intact and actually improves. The low-res version is a real <code>&lt;img&gt;<\/code> tag with <code>alt<\/code> text, indexable by Google Images, with IPTC metadata enabling the \"Licensable\" badge. CSS and JS together weigh about 4 KB with zero dependencies.<\/p><\/dd>\n<dt id=\"what%20does%20a%20visitor%20without%20javascript%20see%3F\"><h3>What does a visitor without JavaScript see?<\/h3><\/dt>\n<dd><p>The sharp, watermarked low-res version. There's never a broken image; canvas reconstruction only happens if JavaScript is active.<\/p><\/dd>\n<dt id=\"does%20bender%20work%20with%20page%20caching%3F\"><h3>Does Bender work with page caching?<\/h3><\/dt>\n<dd><p>Yes: align the token validity (24 hours by default) with your page cache duration.<\/p><\/dd>\n<dt id=\"does%20bender%20require%20special%20hosting%3F\"><h3>Does Bender require special hosting?<\/h3><\/dt>\n<dd><p>No \u2014 only PHP 7.4+ with the GD extension, standard on virtually any WordPress hosting.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.1.9<\/h4>\n\n<ul>\n<li>Fixed the protected frame collapsing to its own aspect ratio instead of the box the theme had set: when the original <code>&lt;img&gt;<\/code> (or its <code>&lt;picture&gt;<\/code> wrapper) carried layout classes or inline styles \u2014 the common <code>width:100%; height:100%; object-fit:cover<\/code> inside a fixed-height container used by carousels, cards and hero sections \u2014 the frame that replaces it now inherits them, so the image keeps the width and height it had before.<\/li>\n<li>Fixed lazy-loading themes and plugins undoing the protection on scroll: <code>data-src<\/code>\/<code>data-srcset<\/code> (and the other usual lazy-load attributes) were left on the tag, so the lazy loader put the original image URL back into <code>src<\/code> as soon as the image entered the viewport.<\/li>\n<\/ul>\n\n<h4>0.1.8<\/h4>\n\n<ul>\n<li>Fixed the \"Custom themes \/ page builders\" fallback (<code>universal_scan<\/code>) leaving <code>&lt;picture&gt;<\/code> elements (responsive images with multiple <code>&lt;source&gt;<\/code> breakpoints, e.g. carousels\/sliders) completely unprotected: the hi-res URLs in the <code>&lt;source&gt;<\/code> tags bypassed the mosaic entirely, and the generated canvas ignored the <code>width<\/code>\/<code>height<\/code> intended for that layout. <code>&lt;picture&gt;<\/code>\/<code>&lt;source&gt;<\/code> are now replaced by the protected frame like a plain <code>&lt;img&gt;<\/code>, and the frame keeps the original <code>width<\/code>\/<code>height<\/code> aspect ratio when set.<\/li>\n<\/ul>\n\n<h4>0.1.7<\/h4>\n\n<ul>\n<li>Fixed the \"Custom themes \/ page builders\" fallback (<code>universal_scan<\/code>, added in 0.1.6): when the only protected image on a page was reached exclusively through this fallback, the mosaic viewer script\/style were enqueued too late to ever be printed (the fallback rewrites the fully-buffered page, which closes after <code>wp_head<\/code>\/<code>wp_footer<\/code> already ran), so visitors saw the static low-res <code>&lt;img&gt;<\/code> with no <code>&lt;canvas&gt;<\/code> upgrade \u2014 the image looked unprotected even though the server-side markup was correct. Assets are now enqueued as soon as the fallback decides to scan the page, before output buffering starts.<\/li>\n<\/ul>\n\n<h4>0.1.6<\/h4>\n\n<ul>\n<li>Added a fallback for custom-coded themes and page builders that print <code>&lt;img&gt;<\/code> tags outside <code>the_content()<\/code>\/<code>the_post_thumbnail()<\/code> (e.g. <code>wp_get_attachment_image()<\/code> called directly, or a raw <code>&lt;img src=\"...\"&gt;<\/code> in a hand-built gallery\/slider): those images were left completely unprotected before, even after marking the attachment as protected. Bender now also scans the fully rendered page and swaps in the protected version for any image it recognizes. New \"Custom themes \/ page builders\" setting to disable this if not needed.<\/li>\n<\/ul>\n\n<h4>0.1.5<\/h4>\n\n<ul>\n<li>Fixed 3 strings (the settings page intro and the \"what it stops\" note) that silently failed to load their bundled translation because the English source used a straight apostrophe (') while the .po files had a typographic one (\u2019). All 6 bundled languages regenerated.<\/li>\n<\/ul>\n\n<h4>0.1.4<\/h4>\n\n<ul>\n<li>Bundled ready-made translations (Italian, Spanish, French, German, Brazilian Portuguese, Chinese Simplified) in <code>languages\/<\/code>, loaded automatically via <code>load_plugin_textdomain()<\/code> \u2014 no need to wait for community translations on translate.wordpress.org.<\/li>\n<\/ul>\n\n<h4>0.1.3<\/h4>\n\n<ul>\n<li>All admin-facing strings (settings page, Media Library column, row\/bulk actions, admin notices, error messages) are now proper English source strings wrapped for translation with the <code>bender-mosaic-image-protection<\/code> text domain, instead of hardcoded Italian. Translators can now localize the plugin via translate.wordpress.org.<\/li>\n<\/ul>\n\n<h4>0.1.2<\/h4>\n\n<ul>\n<li>The fixed values of this edition (6\u00d76 grid, watermark text\/opacity, IPTC copyright\/credit, 24h REST token TTL) are no longer implemented through generically-parameterized helper functions called with constant arguments. Each is now hardcoded directly inside the function that uses it (no unused <code>$n<\/code>\/<code>$opacity<\/code>\/<code>$ttl<\/code>-style parameters left over), so the free codebase itself contains no latent\/dormant configurability for these values.<\/li>\n<\/ul>\n\n<h4>0.1.1<\/h4>\n\n<ul>\n<li>All function, class, define, and option\/transient names now use the <code>bendmoim<\/code>\/<code>BENDMOIM<\/code> prefix (was <code>bender<\/code>\/<code>Bender<\/code>, with one stray <code>pg_rl_<\/code> transient key).<\/li>\n<li>Removed dormant Pro-only code paths from the free codebase (variable grid size, WebP\/PNG atlas formats, customizable watermark\/IPTC text, LSB steganographic watermark, configurable token TTL) instead of merely locking them via options. This edition now hardcodes the free-tier values described in the plugin's own settings screen.<\/li>\n<\/ul>\n\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<\/ul>","raw_excerpt":"Protect your images from scrapers, hotlinking, and theft with mosaic tiling, watermarking, and IPTC copyright metadata \u2014 without hurting SEO or speed.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/fa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/335661","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/fa.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/fa.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=335661"}],"author":[{"embeddable":true,"href":"https:\/\/fa.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/opencluster"}],"wp:attachment":[{"href":"https:\/\/fa.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=335661"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/fa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=335661"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/fa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=335661"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/fa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=335661"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/fa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=335661"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/fa.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=335661"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}