{"id":306734,"date":"2026-07-31T06:08:47","date_gmt":"2026-07-31T06:08:47","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/anytry-ai-virtual-try-on-for-woocommerce\/"},"modified":"2026-07-31T06:08:30","modified_gmt":"2026-07-31T06:08:30","slug":"anytry-ai-virtual-try-on-for-woocommerce","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/anytry-ai-virtual-try-on-for-woocommerce\/","author":21028239,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.21","stable_tag":"1.0.21","tested":"7.0.2","requires":"6.4","requires_php":"7.4","requires_plugins":null,"header_name":"AnyTry - AI Virtual Try-On for WooCommerce","header_author":"Anytry","header_description":"Adds AI-powered virtual try-on functionality to WooCommerce product pages.","assets_banners_color":"010101","last_updated":"2026-07-31 06:08:30","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/anytry.pl\/","header_author_uri":"https:\/\/anytry.pl","rating":0,"author_block_rating":0,"active_installs":0,"downloads":24,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.21":{"tag":"1.0.21","author":"piezak","date":"2026-07-31 06:08:30"}},"upgrade_notice":{"1.0.20":"<p>Maintenance: translations now ship as WordPress.org language packs (no bundled catalogs). Includes the 1.0.19 security &amp; privacy hardening. Recommended update.<\/p>","1.0.16":"<p>Analytics fix: refund\/return values are now reported at the order level \u2014 correct across multiple partial refunds. Recommended update.<\/p>","1.0.15":"<p>Reliability hardening: prevents a duplicate try-on in two rare timing edge cases (removing a saved try-on during a submit, and retry-after-timeout). Recommended update.<\/p>","1.0.14":"<p>Reliability, privacy and accessibility hardening over 1.0.13: stalled downloads now fail fast, Escape mid-generation keeps the job running, analytics only with consent, leftover previews cleared, plus keyboard\/screen-reader support for the try-on dialog. Recommended update.<\/p>","1.0.13":"<p>Fixes for the optional new buttons: the cart Try-On button now works correctly for variable (size \/ colour) products and shows in the mini-cart drawer; the listing button overlay is keyboard-accessible. No change to the core Try-On flow. Recommended update.<\/p>","1.0.12":"<p>WordPress.org compliance + compatibility. The public status\/download REST endpoints declare a public permission_callback (authorization unchanged, still enforced by the AnyTry API). Translatable strings fully extractable; product images validated against the uploads dir. Recommended update.<\/p>","1.0.6":"<p>Accuracy + hardening release. Conversion attribution now counts only tried-on products and emits each purchase once server-side, fixing dashboard inflation and double-counting. Adds server-side image validation and a per-IP rate-limit ceiling. Recommended update.<\/p>","1.0.5":"<p>Adds an on-storefront language switcher (globe) to the Try-On widget. Additive and backward-compatible \u2014 no action required. Recommended update.<\/p>","1.0.4":"<p>WP.org compliance release. <strong>Existing installs<\/strong>: analytics + conversion-attribution are now OFF by default after upgrade \u2014 re-enable at WooCommerce \u2192 AnyTry AI if you use the conversion dashboards. SSE proxy on native PHP streams. Recommended update.<\/p>","1.0.3":"<p>Hardening release. Cancelled-order tracking is now per-(order, product) idempotent so admin status thrash cannot inflate cancellation KPIs. Customer-typed refund reason is no longer forwarded to the AnyTry API (stays in WooCommerce only). Recommended update.<\/p>","1.0.2":"<p>Compliance + hardening release. Analytics is now opt-in (existing installs auto-migrate to ON; new installs default OFF). Removed the freeform Custom CSS textarea. Inline scripts converted to wp_add_inline_script. Per-field sanitisation on cookie \/ POST JSON inputs. Recommended update.<\/p>","1.0.1":"<p>Recommended update for all sites \u2014 significantly improves compatibility with optimizer plugins (Async JavaScript, WP Rocket, LiteSpeed Cache), block themes, and themes with aggressive quickview \/ variant-swap behavior.<\/p>","1.0.0":"<p>Initial stable release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3629431,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3629431,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3629431,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3629431,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.21"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3629431,"resolution":"1","location":"assets","locale":"","width":2000,"height":1560},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3629431,"resolution":"2","location":"assets","locale":"","width":2560,"height":2900},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3629431,"resolution":"3","location":"assets","locale":"","width":2560,"height":1640}},"screenshots":{"1":"Virtual try-on modal \u2014 customer uploads photo and sees AI-generated result.","2":"Admin settings panel \u2014 configure API key, button style, and size advisor.","3":"Product page \u2014 \"Try On\" button integrated with WooCommerce product layout."}},"plugin_section":[],"plugin_tags":[2353,282,7097,148223,286],"plugin_category":[45],"plugin_contributors":[273967],"plugin_business_model":[],"class_list":["post-306734","plugin","type-plugin","status-publish","hentry","plugin_tags-ai","plugin_tags-ecommerce","plugin_tags-fashion","plugin_tags-virtual-try-on","plugin_tags-woocommerce","plugin_category-ecommerce","plugin_contributors-piezak","plugin_committers-piezak"],"banners":{"banner":"https:\/\/ps.w.org\/anytry-ai-virtual-try-on-for-woocommerce\/assets\/banner-772x250.png?rev=3629431","banner_2x":"https:\/\/ps.w.org\/anytry-ai-virtual-try-on-for-woocommerce\/assets\/banner-1544x500.png?rev=3629431","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/anytry-ai-virtual-try-on-for-woocommerce\/assets\/icon-128x128.png?rev=3629431","icon_2x":"https:\/\/ps.w.org\/anytry-ai-virtual-try-on-for-woocommerce\/assets\/icon-256x256.png?rev=3629431","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/anytry-ai-virtual-try-on-for-woocommerce\/assets\/screenshot-1.png?rev=3629431","caption":"Virtual try-on modal \u2014 customer uploads photo and sees AI-generated result."},{"src":"https:\/\/ps.w.org\/anytry-ai-virtual-try-on-for-woocommerce\/assets\/screenshot-2.png?rev=3629431","caption":"Admin settings panel \u2014 configure API key, button style, and size advisor."},{"src":"https:\/\/ps.w.org\/anytry-ai-virtual-try-on-for-woocommerce\/assets\/screenshot-3.png?rev=3629431","caption":"Product page \u2014 \"Try On\" button integrated with WooCommerce product layout."}],"raw_content":"<!--section=description-->\n<p>AnyTry is an AI-powered virtual try-on system that lets your customers see how they'll look wearing your products before they buy. The plugin integrates directly with WooCommerce product pages, adding a \"Try On\" button that uses cutting-edge generative AI.<\/p>\n\n<h3>External services<\/h3>\n\n<p>This plugin connects to the AnyTry API (https:\/\/api.anytry.ai) to generate virtual try-on images using generative AI. Using the plugin requires an AnyTry account (a free trial is available from the plugin settings screen).<\/p>\n\n<p><strong>Endpoints used at api.anytry.ai:<\/strong><\/p>\n\n<p>Service endpoints (the Try-On feature itself; all reachable without analytics opt-in):<\/p>\n\n<ul>\n<li><code>POST \/anytry<\/code> \u2014 submit a virtual try-on job (customer photo + product image, multipart upload).<\/li>\n<li><code>GET \/status\/&lt;job-id&gt;<\/code> \u2014 poll job progress.<\/li>\n<li><code>GET \/status\/stream\/&lt;job-id&gt;<\/code> \u2014 Server-Sent Events stream of progress updates (real-time alternative to polling).<\/li>\n<li><code>POST \/cancel\/&lt;job-id&gt;<\/code> \u2014 cancel an in-flight try-on job when the customer closes the dialog or leaves the page mid-generation, so the reserved GPU work is released.<\/li>\n<li><code>GET &lt;result image&gt;<\/code> \u2014 fetch the finished try-on image. The image URL is returned by <code>\/status<\/code> (<code>download_url<\/code>) and is validated before the plugin fetches it (HTTPS only; host must be <code>api.anytry.ai<\/code> or an <code>*.anytry.ai<\/code> subdomain).<\/li>\n<li><code>POST \/analyze\/size<\/code> \u2014 AI Size Advisor recommendation (only when the merchant has enabled the Size Advisor feature and the customer completes the quiz).<\/li>\n<li><code>POST \/gpu\/warmup<\/code> \u2014 wake up the GPU pool when the customer opens the Try-On modal. No body; optional tracking token only. Reduces first-generation latency.<\/li>\n<\/ul>\n\n<p>Admin-side service endpoints (operator workflow only; not customer-facing):<\/p>\n\n<ul>\n<li><code>POST \/tenant\/trial<\/code> \u2014 create a free-trial account on first plugin activation (admin email + WP username + store domain only).<\/li>\n<li><code>POST \/auth\/register-magic-link<\/code> \u2014 send the activation magic-link email to the operator.<\/li>\n<li><code>POST \/auth\/get-key-by-email<\/code> \u2014 recover the API key for an existing account.<\/li>\n<li><code>POST \/auth\/portal-token<\/code> \u2014 single-sign-on to the AnyTry Portal from the admin Settings page.<\/li>\n<li><code>GET \/account\/status<\/code> \u2014 validate the configured API key.<\/li>\n<li><code>GET \/analytics?days=&lt;N&gt;<\/code> and <code>GET \/analytics\/insights<\/code> \u2014 admin dashboard data (only requested when the operator opens the AnyTry admin Settings page).<\/li>\n<\/ul>\n\n<p>Analytics + conversion-attribution endpoints (gated on analytics consent \u2014 default OFF on new installs):<\/p>\n\n<ul>\n<li><code>POST \/api\/track-event<\/code> \u2014 funnel events (button impressions, generation completes, add-to-cart, checkout-start, purchases, refunds).<\/li>\n<li><code>POST \/api\/abandon<\/code> \u2014 abandon-tracking event when the customer closes the modal mid-generation.<\/li>\n<li><code>POST \/api\/tracking\/lookup<\/code> \u2014 server-side recovery of try-on attribution when cookies are unavailable (REST checkout flows).<\/li>\n<li><code>GET \/api\/tenant\/tracking-token<\/code> \u2014 fetch the per-tenant frontend tracking token (admin Settings page).<\/li>\n<\/ul>\n\n<p>Enable analytics at WooCommerce \u2192 AnyTry AI \u2192 \"Send analytics &amp; conversion events\". The Try-On feature works regardless.<\/p>\n\n<p><strong>What is sent to the AnyTry API:<\/strong><\/p>\n\n<ul>\n<li>The customer photo uploaded via the Try-On modal (transmitted only when the customer explicitly clicks \"Try On\").<\/li>\n<li>The product image URL and product identifier from WooCommerce.<\/li>\n<li>A random session identifier (no personally identifiable information).<\/li>\n<li>WooCommerce order ID and product IDs on order completion \u2014 <strong>only when analytics consent is enabled<\/strong>.<\/li>\n<li>Optional: height, weight, and usual size values the customer enters in the AI Size Advisor quiz.<\/li>\n<\/ul>\n\n<p><strong>When the data is sent:<\/strong><\/p>\n\n<ul>\n<li>Try-On generation: when a customer uploads a photo and clicks \"Try On\" on a product page.<\/li>\n<li>Size Advisor: when a customer completes the AI Size Advisor quiz.<\/li>\n<li>Conversion events: when an order containing a tried-on product is placed \u2014 <strong>only when analytics consent is enabled<\/strong>.<\/li>\n<\/ul>\n\n<p><strong>Cookies (server-set, persistent):<\/strong><\/p>\n\n<ul>\n<li><code>anytry_session<\/code> cookie (90 days) \u2014 stores the random session ID and the list of product IDs the visitor has tried on, used to attribute orders to try-on sessions for the conversion dashboard. <strong>Set only when analytics consent is enabled.<\/strong><\/li>\n<li><code>anytry_tried<\/code> cookie (90 days) \u2014 stores a fallback list of tried product IDs for cases where <code>anytry_session<\/code> is unavailable (third-party cookie blockers, REST checkout flows). <strong>Set only when analytics consent is enabled.<\/strong><\/li>\n<li><code>anytry_legal_accepted_v2<\/code> cookie (1 year) \u2014 remembers that the customer has accepted the Try-On legal\/age-consent overlay so they are not asked again on every page. Set ONLY after the customer clicks \"Accept\" on the legal overlay. Not used for any analytics or attribution.<\/li>\n<\/ul>\n\n<p><strong>Persistent browser storage (localStorage):<\/strong><\/p>\n\n<ul>\n<li><code>anytry_legal_accepted_v2<\/code> \u2014 mirror of the consent cookie above, same purpose, same trigger. No analytics or attribution use.<\/li>\n<li><code>anytry_tried<\/code> \u2014 client-side mirror of the <code>anytry_tried<\/code> cookie value, used when third-party cookies are blocked. <strong>Written only when analytics consent is enabled.<\/strong><\/li>\n<li><code>anytry_tried_products<\/code> \u2014 same purpose as <code>anytry_tried<\/code> but stored in a structured per-product map; used by the admin Conversions tab to attribute orders to try-on sessions. <strong>Written only when analytics consent is enabled.<\/strong><\/li>\n<li><code>anytry_canonical_session_id<\/code> \u2014 a random <code>sess_*<\/code> identifier kept across reloads so the API can JOIN a try-on generation event to a later purchase event for conversion attribution. <strong>Persisted only when analytics consent is enabled.<\/strong> When consent is off, an ephemeral id is held in memory for the current page only and never written to localStorage.<\/li>\n<li><code>anytry_active_jobs<\/code> \u2014 short-lived registry of in-flight try-on jobs (job IDs + status), used so the floating \"still working\u2026\" widget can resume after a page reload. Cleared when the job finishes or after 24 hours. Not used for any analytics or attribution.<\/li>\n<\/ul>\n\n<p><strong>Ephemeral per-tab storage (sessionStorage):<\/strong><\/p>\n\n<p>These are scoped to the current browser tab and discarded the moment the tab closes. They exist purely to keep the Try-On UI responsive during a single visit and are never sent to any server.<\/p>\n\n<ul>\n<li><code>anytry_before_&lt;jobId&gt;<\/code> \u2014 the photo the customer uploaded, kept so the \"before \/ after\" toggle works after a result is generated.<\/li>\n<li><code>anytry_result_&lt;jobId&gt;<\/code> and <code>anytry_result_image<\/code> \u2014 the generated result image data URL, used so the same result re-renders instantly when the customer reopens the modal in the same tab.<\/li>\n<li><code>anytry_feedback_state<\/code> \u2014 whether the customer already rated \ud83d\udc4d \/ \ud83d\udc4e the current result.<\/li>\n<li><code>anytry_quiz_user_height<\/code>, <code>anytry_quiz_user_weight<\/code>, <code>anytry_quiz_usual_size<\/code>, <code>anytry_quiz_skipped<\/code> \u2014 Size Advisor quiz answers, kept so the customer doesn't have to re-enter them while comparing multiple try-ons.<\/li>\n<li><code>anytry_sw_blocks_sse<\/code> \u2014 internal counter the plugin uses to detect a Service Worker that's blocking real-time updates, so it can transparently fall back to the same-origin SSE proxy on the next try-on.<\/li>\n<\/ul>\n\n<p><strong>Persistent browser storage (IndexedDB):<\/strong><\/p>\n\n<p>Used as a local image cache to avoid re-downloading the same files. Both stores live entirely in the visitor's browser, are never sent to any server, and are removed when the customer clears their browser data.<\/p>\n\n<ul>\n<li><code>anytry_cache<\/code> \u2192 object store <code>photos<\/code> \u2014 the most recent uploaded photo, so reopening the modal restores the previous photo selection without a re-pick.<\/li>\n<li><code>anytry_results<\/code> \u2192 object store <code>images<\/code> \u2014 the data URL of generated result images keyed by job ID, so revisiting a recently-generated try-on renders instantly.<\/li>\n<\/ul>\n\n<p><strong>Analytics consent:<\/strong><\/p>\n\n<p>The plugin does NOT send analytics or conversion-attribution events by default. Enable them at WooCommerce \u2192 AnyTry AI \u2192 \"Send analytics &amp; conversion events\". The Try-On image generation itself works whether or not this is enabled \u2014 only the conversion-attribution dashboard in the AnyTry Portal depends on this opt-in.<\/p>\n\n<p><strong>Optional Google Fonts (default OFF):<\/strong><\/p>\n\n<p>By default the plugin uses system-sans typography and makes NO third-party font request \u2014 the AnyTry API is the only external service it contacts. An internal <code>anytry_load_google_font<\/code> option (OFF by default, with no user-facing control) would, if enabled, request the Outfit web font from Google Fonts (https:\/\/fonts.googleapis.com) on the storefront and the AnyTry admin Settings page; it stays off in a standard install.<\/p>\n\n<ul>\n<li>Service: Google Fonts (https:\/\/fonts.google.com)<\/li>\n<li>Data sent: visitor IP and User-Agent (standard HTTP request) at the moment a page that has this option enabled is rendered<\/li>\n<li>Terms of Service: https:\/\/policies.google.com\/terms<\/li>\n<li>Privacy Policy: https:\/\/policies.google.com\/privacy<\/li>\n<\/ul>\n\n<p>Uploaded photos are automatically deleted from the AnyTry servers within 5 minutes of processing and are not used to train AI models.<\/p>\n\n<p>This service is provided by AnyTry. By using the plugin, customers agree to the AnyTry Terms of Service and Privacy Policy:<\/p>\n\n<ul>\n<li>Terms of Service: https:\/\/anytry.pl\/terms<\/li>\n<li>Privacy Policy: https:\/\/anytry.pl\/privacy<\/li>\n<\/ul>\n\n<p><strong>Key Features:<\/strong><\/p>\n\n<ul>\n<li><strong>Photorealistic Try-On<\/strong> \u2014 Uses generative AI to create realistic images of customers wearing your products.<\/li>\n<li><strong>Data Privacy<\/strong> \u2014 Customer photos are automatically deleted after processing. No biometric data stored. Try-on tracking data stored on orders (session ID, tried-product list, attribution job IDs) is included in WooCommerce's built-in personal-data Export and Erase tools, so customer data requests cover it.<\/li>\n<li><strong>High Performance<\/strong> \u2014 Real-time SSE streaming with a polling fallback; doesn't burden your hosting.<\/li>\n<li><strong>Responsive Design<\/strong> \u2014 Works perfectly on mobile and desktop devices.<\/li>\n<li><strong>Variant Support<\/strong> \u2014 Works with simple and variable products (color\/size).<\/li>\n<li><strong>AI Size Advisor<\/strong> \u2014 Size recommendations from a short quiz (height and weight with photo silhouette analysis, or a single \"what size do you wear?\" question).<\/li>\n<li><strong>Multilingual<\/strong> \u2014 The shopper widget ships 10 languages (EN, PL, DE, UK, IT, ES, FR, SV, DA, NB); admin settings are English, with translations delivered via WordPress.org language packs.<\/li>\n<li><strong>HPOS Compatible<\/strong> \u2014 Full support for WooCommerce High-Performance Order Storage.<\/li>\n<li><strong>WooCommerce Blocks<\/strong> \u2014 Compatible with the new block-based checkout.<\/li>\n<li><strong>Multi-Job Navigation<\/strong> \u2014 Compare results from multiple try-ons with swipe navigation.<\/li>\n<\/ul>\n\n<p><strong>How It Works:<\/strong><\/p>\n\n<ol>\n<li>Customer clicks \"Try On\" on a product page.<\/li>\n<li>They upload a photo of themselves.<\/li>\n<li>AI generates a photorealistic image of them wearing the product.<\/li>\n<li>Optional: AI Size Advisor recommends the best size.<\/li>\n<\/ol>\n\n<p><strong>SaaS Model:<\/strong> This plugin connects to the <a href=\"https:\/\/api.anytry.ai\">AnyTry API<\/a> for AI processing. An API key is required (free trial available). See <a href=\"https:\/\/anytry.pl\/terms\">Terms of Service<\/a> and <a href=\"https:\/\/anytry.pl\/privacy\">Privacy Policy<\/a>.<\/p>\n\n<h3>Configuration<\/h3>\n\n<ol>\n<li>Navigate to WooCommerce &gt; AnyTry AI in the admin panel.<\/li>\n<li>Enter your API key or start a free trial.<\/li>\n<li>Customize the button appearance (color, text, position).<\/li>\n<li>Enable AI Size Advisor (optional).<\/li>\n<li>Ensure your products have featured images set (flat-lay or ghost mannequin photos work best).<\/li>\n<\/ol>\n\n<h3>Requirements<\/h3>\n\n<ul>\n<li>WordPress 6.4 or newer.<\/li>\n<li>WooCommerce 5.0 or newer.<\/li>\n<li>PHP 7.4+ (recommended: 8.1+).<\/li>\n<li>Active internet connection (for API communication).<\/li>\n<\/ul>\n\n<h3>Source code &amp; build<\/h3>\n\n<p>The plugin distribution includes the full unminified source under <code>src\/js\/anytry.js<\/code> and <code>src\/css\/anytry.css<\/code> alongside the minified runtime assets in <code>assets\/<\/code> \u2014 this satisfies the WordPress.org source-visibility guideline. The minified files are generated from those sources with the <code>minify_wp.js<\/code> build script. The build\/development tooling lives in the plugin's source repository and is intentionally <strong>not<\/strong> bundled in the distributed ZIP (only plugin runtime + the unminified <code>src\/<\/code> sources ship); the build process is documented below so anyone can reproduce the minified assets from source.<\/p>\n\n<p>Build steps (run from a checkout of the plugin's source repository, where the <code>tools\/<\/code> directory is present):<\/p>\n\n<ol>\n<li><code>cd &lt;repo-root&gt;\/tools\/<\/code><\/li>\n<li><code>npm install esbuild<\/code> (one-time)<\/li>\n<li><code>node minify_wp.js<\/code><\/li>\n<\/ol>\n\n<p>Build dependencies: Node.js 18+ and esbuild. The build script (<code>tools\/minify_wp.js<\/code>) generates 5 minified files from 5 sources:<\/p>\n\n<ul>\n<li><code>src\/js\/anytry.js<\/code> \u2192 <code>assets\/js\/anytry.min.js<\/code> (storefront runtime)<\/li>\n<li><code>src\/css\/anytry.css<\/code> \u2192 <code>assets\/css\/anytry.min.css<\/code> (storefront styles)<\/li>\n<li><code>src\/css\/anytry-admin.css<\/code> \u2192 <code>assets\/css\/anytry-admin.min.css<\/code> (admin Settings page styles)<\/li>\n<li><code>assets\/js\/anytry-admin-settings.js<\/code> \u2192 <code>assets\/js\/anytry-admin-settings.min.js<\/code> (admin Settings page helpers; small enough that the unminified source lives in <code>assets\/<\/code> directly rather than <code>src\/<\/code>)<\/li>\n<li><code>assets\/js\/anytry-admin-packshot.js<\/code> \u2192 <code>assets\/js\/anytry-admin-packshot.min.js<\/code> (WP media-library hook for the admin \"Packshot\" picker on product edit screens; small enough that the unminified source lives in <code>assets\/<\/code> directly rather than <code>src\/<\/code>)<\/li>\n<\/ul>\n\n<p>Third-party libraries shipped with the plugin:<\/p>\n\n<ul>\n<li><code>assets\/js\/heic2any.min.js<\/code> \u2014 heic2any v0.0.4 (MIT licensed). Upstream repository: https:\/\/github.com\/alexcorvi\/heic2any. Used for client-side HEIC \u2192 JPEG conversion before upload (iPhone camera output). Lazy-loaded only when the customer selects an HEIC file; can be disabled via the \"iPhone HEIC support\" toggle in WooCommerce \u2192 AnyTry AI settings.<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Download the plugin ZIP file.<\/li>\n<li>In WordPress admin, go to Plugins &gt; Add New &gt; Upload Plugin.<\/li>\n<li>Select the file and click Install.<\/li>\n<li>Activate the plugin.<\/li>\n<li>Go to WooCommerce &gt; AnyTry AI to configure your API key.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"are%20customer%20photos%20safe%3F\"><h3>Are customer photos safe?<\/h3><\/dt>\n<dd><p>Yes. Photos are transmitted over encrypted connections, processed by AI, and automatically deleted from the server within 5 minutes. They are not used to train AI models.<\/p><\/dd>\n<dt id=\"why%20does%20generation%20take%20a%20few%20seconds%3F\"><h3>Why does generation take a few seconds?<\/h3><\/dt>\n<dd><p>The system creates an entirely new image using generative AI. This is a complex computational process that ensures a unique, personalized result.<\/p><\/dd>\n<dt id=\"what%20kind%20of%20photos%20should%20customers%20upload%3F\"><h3>What kind of photos should customers upload?<\/h3><\/dt>\n<dd><p>Best results come from full-body photos with good lighting on a plain background.<\/p><\/dd>\n<dt id=\"does%20this%20plugin%20store%20any%20data%20locally%3F\"><h3>Does this plugin store any data locally?<\/h3><\/dt>\n<dd><p>The plugin stores only its WooCommerce configuration options (API key, button style, size advisor mode, etc.) and a small amount of WooCommerce order metadata for conversion attribution. No customer photos and no analytics tables are persisted on the merchant site \u2014 all AI processing and analytics are handled by the AnyTry cloud service.<\/p><\/dd>\n<dt id=\"does%20this%20plugin%20set%20tracking%20cookies%3F\"><h3>Does this plugin set tracking cookies?<\/h3><\/dt>\n<dd><p>Only when the merchant has enabled analytics consent (default OFF). When enabled, <code>anytry_session<\/code> and <code>anytry_tried<\/code> cookies persist for 90 days on visitor browsers \u2014 both store a random session ID and a list of product IDs the visitor has tried on, used to attribute purchases to try-on sessions. See the \"External services\" section for full disclosure.<\/p><\/dd>\n<dt id=\"is%20this%20compatible%20with%20hpos%3F\"><h3>Is this compatible with HPOS?<\/h3><\/dt>\n<dd><p>Yes. The plugin is fully compatible with WooCommerce High-Performance Order Storage (HPOS).<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.21<\/h4>\n\n<ul>\n<li>Reliability: the try-on window can no longer end up in a contradictory minimized-yet-open state. Re-showing the window cleared the internal flag but left the minimized marker on the element, so which state won was decided only by stylesheet order \u2014 a reorder would have hidden both the window and the floating progress bubble at once, leaving no way back except the Try-On button.<\/li>\n<li>Reliability: the background-jobs view no longer dismantles the window (hiding the result, the upload area and the floating bubble) before checking whether it has anything to display, which could leave an empty white window.<\/li>\n<li>Reliability: switching from one product to another now always shows the correct product's size options \u2014 or none, when the Size Advisor is turned off \u2014 instead of briefly carrying over the previous product's size choices.<\/li>\n<li>Reliability: switching to a different product while a result is still downloading no longer shows the wrong product's result or freezes the try-on that is still running.<\/li>\n<li>Reliability: opening the same store in two browser tabs no longer lets one tab cancel or drop the other tab's in-progress \u2014 and already paid-for \u2014 try-on.<\/li>\n<li>Reliability: a finished try-on is now picked up correctly after a phone browser tab is briefly frozen in the background and reopened, instead of appearing stuck.<\/li>\n<li>Reliability: the Save button, and restoring a saved try-on, no longer hang on browsers where the local image store is slow or blocked to open \u2014 the widget now falls back to fetching the result instead of waiting indefinitely.<\/li>\n<li>Reliability: a size suggestion that arrives late no longer appears on top of an error screen.<\/li>\n<li>Reliability: a finished try-on shown in the multi-item comparison list now becomes clickable on its own, instead of remaining on \"loading result\u2026\".<\/li>\n<li>Reliability: a temporary network or CDN hiccup while fetching a finished try-on no longer shows a dead error. The widget now retries the same, already-generated result a few times before giving up \u2014 it never re-runs or re-charges the try-on. This closes the most common \"generated but not shown\" case.<\/li>\n<li>Diagnostics: clearer error categories (a connection problem is now labelled as such, an unsupported image as an image problem, instead of a generic \"unknown\"), and error events now include the try-on identifier so a store can see exactly which requests hit a display problem.<\/li>\n<\/ul>\n\n<h4>1.0.20<\/h4>\n\n<ul>\n<li>Maintenance: translations now follow the standard WordPress.org model \u2014 the plugin ships English source text, and translations are delivered as community language packs from translate.wordpress.org rather than as catalogs bundled inside the plugin. No change to any feature or behaviour.<\/li>\n<li>Compatibility: verified on WordPress 7.0.2 with PHP 7.4 through 8.5.<\/li>\n<\/ul>\n\n<h4>1.0.19<\/h4>\n\n<ul>\n<li>Security: try-on and size requests now require a real, published, try-on-enabled product and no longer accept a caller-supplied product image, preventing use of the paid try-on pipeline outside the intended flow.<\/li>\n<li>Security: an anonymous request can no longer change the store-wide streaming-proxy setting, and malformed job tokens are now rejected instead of silently ignored.<\/li>\n<li>Privacy: with analytics turned off, the storefront now writes no tracking cookie, local storage, or data-layer event.<\/li>\n<li>Privacy: Size Advisor now stays fully disabled on both the storefront and the server when turned off in settings.<\/li>\n<li>Privacy: GDPR order-data erasure now reliably removes all AnyTry order data.<\/li>\n<li>Privacy: cancellation and refund analytics are now limited to products the shopper actually tried on.<\/li>\n<li>Reliability: the page-resume mini widget loads its stylesheet correctly, cancels only its own job when closed, and clears that job's cached photo and result.<\/li>\n<li>Admin: the Data controller example now suggests your own store name.<\/li>\n<li>Maintenance: refreshed bundled translations and added third-party licence notices; aligned the main bundle version banner.<\/li>\n<li>Compatibility: removed global PHP <code>ini_set()<\/code> overrides (max_execution_time \/ default_socket_timeout) that could push a host out of its configured limits \u2014 the request timeout is set on the HTTP call itself, and the live-status stream now restores its output settings on shutdown.<\/li>\n<\/ul>\n\n<h4>1.0.18<\/h4>\n\n<ul>\n<li>Reliability: HEIC\/HEIF photo uploads no longer emit a PHP notice during image-type detection on the try-on request (the image-info value is now always initialised).<\/li>\n<li>Maintenance: internal static-analysis hardening (PHPStan level 5, clean) and minor type-safety cleanups \u2014 no change to behaviour.<\/li>\n<\/ul>\n\n<h4>1.0.17<\/h4>\n\n<ul>\n<li>Reliability: made result finalization idempotent so a very slow result download can no longer render twice or double-count a completion.<\/li>\n<li>Privacy: swapping to a new photo now clears the previous try-on's cached result images from the browser immediately (previously cleared only on closing the try-on window).<\/li>\n<li>Accuracy: eyewear auto-detection on shop\/quick-view cards no longer reads a neighbouring product's description.<\/li>\n<li>Hardening: strip line breaks from the product category before it is sent to the API; apply the same Cloudflare source-IP verification to the conversion-tracking rate limit as the rest of the plugin.<\/li>\n<\/ul>\n\n<h4>1.0.16<\/h4>\n\n<ul>\n<li>Analytics: refund\/return events now report the order-level cumulative refunded value (the sum across all of an order's refunds), fixing under-reporting on orders with multiple sequential partial refunds.<\/li>\n<li>Analytics: purchase attribution is now precise per tried product. When cookie-based tracking is lost (e.g. block-based checkout, privacy mode, cross-device), the plugin now recovers which of the purchased items were actually tried on \u2014 over a 90-day window \u2014 and reports each item's own value, instead of falling back to the whole basket. Purchases where no tried-on product was bought are no longer counted, so reported conversion value and counts reflect only genuine try-on-driven sales.<\/li>\n<li>Admin: the Size Advisor settings now include a short note describing the Eye Advisor \u2014 AnyTry's automatic eyewear frame-fit check shown on the try-on result for glasses and sunglasses.<\/li>\n<\/ul>\n\n<h4>1.0.15<\/h4>\n\n<ul>\n<li>Reliability: closed three rare timing edge cases around a running try-on \u2014 removing one saved try-on while another was still being submitted; retrying after a connection timeout (the retry now reconnects to the in-progress try-on instead of starting a fresh one); and re-opening the try-on while one is already running (it now restores the running try-on instead of cancelling it).<\/li>\n<li>Size Advisor: split top\/bottom and eyewear-fit recommendations now persist correctly across saved try-ons \u2014 they no longer collapse to a single size or display incorrectly when switching between results.<\/li>\n<\/ul>\n\n<h4>1.0.14<\/h4>\n\n<ul>\n<li>Privacy (GDPR): analytics attribution is now written to the order only when the shopper has given analytics consent; and any leftover try-on preview images are cleared from the browser's local storage on the next visit, so results are not retained longer than needed.<\/li>\n<li>Reliability: a try-on download that stalls mid-transfer now fails fast instead of spinning forever; pressing Escape while a try-on is still generating minimises it (the job keeps running) instead of closing and abandoning it; the daily free-try counter is now retry-safe so a network retry cannot double-count; and closing the window signals the server to cancel an in-flight job.<\/li>\n<li>Accessibility: broad keyboard and screen-reader improvements to the try-on dialog \u2014 focus moves into the dialog on open and returns to the launching button on close, focus stays trapped inside while it is open, progress updates are announced, keyboard focus outlines are visible, toggle buttons expose their pressed\/expanded state, all controls are keyboard-operable, and animations respect the system \"reduce motion\" setting.<\/li>\n<li>Fix: after deleting saved try-ons down to a single result, the result card no longer shows leftover carousel navigation dots.<\/li>\n<li>Security \/ hardening: admin credential and settings changes now require full administrator capability; the internal service-worker diagnostic report is rate-limited per IP; and the translation text domain is loaded so non-Polish locales display correctly.<\/li>\n<\/ul>\n\n<h4>1.0.13<\/h4>\n\n<ul>\n<li>Fix: the cart Try-On button now resolves the parent product for variable products (size \/ colour variants) \u2014 the category allowlist, the per-product exclusion list, and AI category routing now work correctly when a shopper opens Try-On from a cart line. Previously variations could be filtered out or mis-categorised.<\/li>\n<li>Fix (security \/ cost): the server-side product-exclusion check now resolves variations to their parent, so a product you have excluded can no longer be tried on (and billed) when launched from a cart line \u2014 the exclusion is now enforced on the job request, not just on the button.<\/li>\n<li>Quality: try-ons launched from the WooCommerce block cart (the default cart) now send the correct product category to the AI. Previously the block cart sent none \u2014 which could route garments to the fallback model and skip per-category settings. Classic cart, single product and listing were already correct; this brings the block cart in line.<\/li>\n<li>Fix: the listing button overlay is now keyboard-accessible (focusable + Enter \/ Space) \u2014 the optional \"show on hover\" mode no longer hides it from keyboard and screen-reader users.<\/li>\n<li>Fix: the Cart-block Try-On button now also appears in the mini-cart slide-out drawer on block themes.<\/li>\n<li>Compatibility: on block \/ full-site-editing themes (incl. the WordPress defaults Twenty Twenty-Four \/ Twenty Twenty-Five), the single-product Try-On button now appears reliably even when the theme hydrates the Add-to-Cart button after the page scripts load \u2014 previously it could be missing entirely on those themes.<\/li>\n<li>Housekeeping: all Button-Visibility options (incl. the image-format converter toggle) are removed on uninstall.<\/li>\n<\/ul>\n\n<h4>1.0.12<\/h4>\n\n<ul>\n<li>Compliance (WP.org review): the storefront status \/ download REST endpoints now declare an explicit public permission_callback (__return_true), matching their intended use \u2014 unauthenticated shoppers checking and fetching their own try-on result. Authorization is unchanged and stays server-side (the unguessable per-job token and the tenant key, validated by the AnyTry API); the per-request rate limit simply moved from the route into each handler. No change to the Try-On flow.<\/li>\n<li>Compliance (i18n): the storefront language bundle no longer passes a runtime variable to a translation function, so every translatable string is now statically extractable by the translation tools. The displayed translations are unchanged.<\/li>\n<li>Compatibility: server-resolved product images are now validated against the WordPress uploads directory (wp_upload_dir()) instead of the site root, so stores whose uploads live outside the WordPress folder no longer have valid product images rejected; the path check is also tightened with realpath() containment.<\/li>\n<\/ul>\n\n<h4>1.0.11<\/h4>\n\n<ul>\n<li>New: optional Try-On button on each product in the cart (WooCommerce -&gt; AnyTry -&gt; Button Visibility -&gt; Cart page items). Off by default. Works on both the classic cart and the block (React) Cart.<\/li>\n<\/ul>\n\n<h4>1.0.10<\/h4>\n\n<ul>\n<li>New: choose where the \"Try On\" button sits on shop and category pages \u2014 pick from nine positions (corners, edges or center) over each product image, under WooCommerce \u2192 AnyTry \u2192 Button Visibility.<\/li>\n<li>New: optional \"show on hover only\" mode reveals the listing button when a shopper hovers a product on desktop, while keeping it always visible on touch devices.<\/li>\n<li>Fix: turning off \"Listing \/ Archive \/ Cart\" now fully hides the listing button. Previously, on a configured store, an unstyled button could still appear on shop and cart pages even when the option was unchecked.<\/li>\n<li>Compatibility: more reliable listing-button placement on Flatsome and other themes that use a custom product-card layout.<\/li>\n<\/ul>\n\n<h4>1.0.9<\/h4>\n\n<ul>\n<li>Fix: the registration screen no longer mislabels a brand-new account as a pre-existing one. When you register and your API key is issued instantly, the plugin now confirms the account was created and the key is active \u2014 previously it said \"account already exists \/ API key retrieved\", which made first-time setup confusing.<\/li>\n<li>Improvement: the account-email field now explains which address to use (the email you first contacted AnyTry with) and notes that the API key activates instantly for a new store.<\/li>\n<\/ul>\n\n<h4>1.0.8<\/h4>\n\n<ul>\n<li>Fix: try-on results no longer occasionally show a \"result not available\" message when the shopper switches away from the tab (or locks their phone) while the image is being generated and returns a few minutes later. The plugin now re-checks and fetches the finished result the moment the tab becomes active again \u2014 including after using the browser's back\/forward buttons.<\/li>\n<li>Fix: saving the result to the device now always uses the copy already held in the browser (in memory or local storage), so the Save button keeps working even after the temporary server copy has expired.<\/li>\n<li>Privacy: the try-on tracking data the plugin stores on orders (session ID, tried-product list, attribution job IDs) is now included in WooCommerce's built-in personal-data Export and Erase tools, so a customer data request (export or erasure) covers it.<\/li>\n<li>Accessibility: the virtual try-on dialog is now correctly exposed to screen readers while open (it was previously hidden from assistive technology).<\/li>\n<li>Fix: the \"Add to cart\" conversion event is no longer double-counted on WooCommerce stores (the server-side and in-page trackers were both firing).<\/li>\n<li>Fix: the try-on button now appears on product pages built with block\/Full-Site-Editing themes (previously it could be missing there).<\/li>\n<\/ul>\n\n<h4>1.0.7<\/h4>\n\n<ul>\n<li>Fix (billing): canceling an in-progress try-on now reliably reaches the server, so a canceled job is no longer charged. The cancel request previously had no server handler registered, so the queued job could complete and consume a credit even after the shopper canceled.<\/li>\n<li>Performance: purchase events are now sent off the checkout thread (via WooCommerce's Action Scheduler when available), so order completion and admin order saves no longer wait on the analytics call. Refund and cancellation events are unchanged.<\/li>\n<li>Security (defence-in-depth): added per-source-IP limits to the same-origin streaming, cancel, and event-tracking endpoints (so they cannot be bypassed by rotating a cookie); outbound API requests no longer follow redirects; and plugin removal is now hardened against symlinked cache directories. Authoritative limits remain server-side.<\/li>\n<li>Privacy: deleting the plugin now also removes the per-visitor try-on session identifier stored on orders, alongside the other plugin data it already cleans up.<\/li>\n<li>Maintenance: hardened the upgrade\/migration runner (single-run guard + safer version advance) and added a timeout to the language-bundle fetch so a stalled request can no longer leave the language switcher unresponsive.<\/li>\n<li>Reliability (mobile \/ iOS Safari): the try-on status stream now escalates to status polling if the connection stalls without ever opening (a silent-hang pattern seen on some iOS Safari \/ service-worker setups), so a generation no longer appears to freeze until the safety timeout. The in-modal language menu now also closes on tap-outside and the Escape key, fixing a case where it could stay open on iPhone.<\/li>\n<li>Compatibility: minimum WordPress raised to 6.4. The plugin already used a few 6.4+ APIs behind version guards; this aligns the declared requirement with them.<\/li>\n<\/ul>\n\n<h4>1.0.6<\/h4>\n\n<ul>\n<li>Fix (attribution accuracy): purchase tracking now counts only the products a shopper actually tried on. Previously, when the per-product try-on list could not be recovered at checkout but a try-on session was detected, every item in the order could be counted as a try-on purchase \u2014 inflating the conversion and attributed-revenue figures in the dashboard. Attribution is now a strict intersection against the order's real line items.<\/li>\n<li>Fix (no double-count): purchase events are now emitted once, server-side, from the order's actual line items. The duplicate client-side emit on the order-received page has been removed \u2014 it keyed on the displayed order number, which on stores using a sequential-order-number plugin differs from the internal order ID and could not always be de-duplicated, double-booking conversions. Try-On \/ status \/ download behaviour is unchanged.<\/li>\n<li>Fix (refunds): partial refunds are now reported only for orders that involved a try-on, matching the full-refund behaviour (previously every partial refund in the store emitted a return event).<\/li>\n<li>Security (defence-in-depth): uploaded images are now validated for pixel dimensions server-side (very large images are rejected) and HEIC\/HEIF uploads are verified by magic bytes rather than filename alone. A per-source-IP ceiling now backs the existing per-session rate limit on job submission so it cannot be bypassed by rotating a cookie. The authoritative content and per-tenant limits remain server-side.<\/li>\n<li>Fix (language switcher): the language dropdown no longer appears already-open when the Try-On window first opens. Accepting the consent screen restored the modal's hidden content and inadvertently forced the (self-managed) language menu open; it now stays closed until the globe is tapped. Affected every first-time open, independent of language.<\/li>\n<\/ul>\n\n<h4>1.0.5<\/h4>\n\n<ul>\n<li>Feature: storefront language switcher. The Try-On widget now shows a globe button that lets shoppers switch the widget's language directly on the product page, independent of the store's language. Translations are served from the plugin's bundled locale catalogs (10 languages) through a public, read-only, rate-limited REST endpoint (<code>anytry\/v1\/lang-bundle<\/code>); the two-letter language code is validated against an on-disk allowlist. The switcher is wrapped in its own error boundary so it can never interfere with the core Try-On flow, and the Try-On \/ status \/ download behaviour is unchanged.<\/li>\n<li>Compliance (WP.org review R <code>\u2026\/piezak\/24May26\/T1<\/code>): the entire development &amp; build tooling directory (<code>tools\/<\/code>) is now excluded from the distribution ZIP per WordPress.org packaging guidance \u2014 the prior package leaked build\/test scripts (<code>minify_wp.cjs<\/code>, smoke\/matrix <code>.sh<\/code>, <code>.py<\/code>, <code>.mjs<\/code>, <code>.yml<\/code>, <code>.log<\/code>) that are not plugin runtime files. The unminified <code>src\/<\/code> sources still ship and the build process stays documented under \"Source code &amp; build\", so the minified assets remain fully reproducible.<\/li>\n<li>Compliance: the bundled heic2any third-party library banner now points at the upstream repository (<code>https:\/\/github.com\/alexcorvi\/heic2any<\/code>); the stale fork URL that returned 404 is gone from every shipped file, not just readme.txt.<\/li>\n<\/ul>\n\n<h4>1.0.4<\/h4>\n\n<ul>\n<li>Compliance (WP.org review R <code>\u2026\/piezak\/24May26\/T1<\/code>): the prior 1.0.2 upgrade migration that auto-enabled analytics + conversion-attribution for existing installs has been removed. Analytics consent now defaults OFF for ALL installs (new + upgraded). Self-hosted operators upgrading from a pre-1.0.4 release must re-enable at WooCommerce \u2192 AnyTry AI \u2192 \"Send analytics &amp; conversion events\" if they want the conversion dashboards to keep populating.<\/li>\n<li>Compliance: the SSE same-origin proxy (<code>ajax_stream_status<\/code>) was rewritten to use native PHP streams (fopen + stream_context_create) instead of cURL. wp_remote_*() cannot stream chunks back live as they arrive (it buffers the entire response); PHP streams are the documented escape hatch for streaming use cases. SSRF + timeout + nonce + rate-limit defenses preserved.<\/li>\n<li>Compliance: removed the <code>load_plugin_textdomain()<\/code> call. Since WordPress 4.6 translations are auto-loaded by WP core for plugins hosted on WordPress.org, and our <code>Requires at least: 5.8<\/code> covers this entirely.<\/li>\n<li>Compliance: all internal transient keys renamed from the 2-char <code>at_*<\/code> prefix to the canonical 6-char <code>anytry_*<\/code> prefix (<code>at_burst_*<\/code>, <code>at_daily_*<\/code>, <code>at_burst_sse_*<\/code>, <code>at_swbeacon_*<\/code>, <code>at_burst_default_*<\/code>). Transients have explicit TTLs so no DB migration is needed \u2014 existing keys expire naturally.<\/li>\n<li>Distribution: the build helper <code>tools\/minify_wp.cjs<\/code> was renamed to <code>tools\/minify_wp.js<\/code>. CommonJS semantics are unchanged (tools\/package.json has no <code>\"type\": \"module\"<\/code>).<\/li>\n<li>Documentation: the heic2any third-party-library attribution in the \"Source code &amp; build\" section now points at the upstream repository (https:\/\/github.com\/alexcorvi\/heic2any).<\/li>\n<\/ul>\n\n<h4>1.0.3<\/h4>\n\n<ul>\n<li>Hardening: cancelled-order tracking is now per-(order, product) idempotent. A new internal table (<code>{prefix}anytry_cancellations<\/code>, UNIQUE on (order_id, product_id)) gates <code>track_cancelled_event<\/code> so admin status thrash (Cancelled \u2192 revert \u2192 Cancelled) cannot inflate the portal \"Cancelled orders\" KPI by N \u00d7 tried products. Mirrors the PrestaShop module's parallel fix. Idempotent migration via <code>dbDelta<\/code> \u2014 no-op when the table already exists.<\/li>\n<li>Hardening: the cancellation hook now skips the local idempotency latch when the API call fails. Combined with the API-side <code>ON CONFLICT DO NOTHING<\/code> semantics, this closes a silent event-loss path under transient API outages.<\/li>\n<li>Hardening: GDPR refund-tracking field minimization \u2014 the customer-typed refund reason is no longer forwarded to api.anytry.ai (it stays in the WooCommerce order data on the merchant site only).<\/li>\n<\/ul>\n\n<h4>1.0.2<\/h4>\n\n<ul>\n<li>Compliance: analytics + conversion-attribution events are now opt-in (default OFF on new installs). Enable at WooCommerce \u2192 AnyTry AI \u2192 \"Send analytics &amp; conversion events\". The Try-On feature works regardless of this setting.<\/li>\n<li>Compliance: the 90-day <code>anytry_session<\/code> cookie is now only set after analytics consent is granted.<\/li>\n<li>Compliance: removed the freeform Custom CSS textarea \u2014 use the structured colour pickers, radius slider, and the active theme's stylesheet for visual customisation. Per-merchant accent \/ radius settings are unchanged.<\/li>\n<li>Compliance: removed dead local-analytics scaffolding (<code>increment_daily_stat<\/code>, <code>record_local_conversion<\/code>, <code>maybe_create_tables<\/code>) that had been kept as no-ops since v2.5; all analytics is centralised at api.anytry.ai.<\/li>\n<li>Compliance: 3 inline <code>&lt;script&gt;<\/code> echoes converted to <code>wp_register_script<\/code> + <code>wp_add_inline_script<\/code> (canonical WP enqueue pattern). The post-install \/ post-upgrade redirect now uses server-side <code>wp_safe_redirect<\/code> at <code>admin_init<\/code>.<\/li>\n<li>Hardening: per-field sanitisation on cookie + POST JSON payloads (<code>sanitize_session_array<\/code> helper). Cookie key debug logging now wraps with <code>sanitize_key<\/code>. The <code>anytry_vip_secret<\/code> register_setting callback uses <code>sanitize_text_field<\/code> (was <code>sanitize_key<\/code>, which mutated secrets).<\/li>\n<li>Distribution: full unminified <code>src\/<\/code> directory and <code>tools\/minify_wp.js<\/code> build script are now included in the plugin ZIP (per WP.org source-visibility guideline). See the new \"Source code &amp; build\" section.<\/li>\n<li>Distribution: the build script now also generates <code>assets\/js\/anytry-admin-packshot.min.js<\/code> from <code>assets\/js\/anytry-admin-packshot.js<\/code> (was previously hand-maintained alongside its source; the .min is now reproducible from the .js).<\/li>\n<li>Documentation: readme.txt now enumerates every endpoint contacted at api.anytry.ai, every cookie \/ localStorage \/ sessionStorage \/ IndexedDB key the plugin writes on the visitor's browser, and the heic2any third-party library attribution.<\/li>\n<li>Hardening: every read of the <code>anytry_api_url<\/code> wp_option now goes through <code>AnyTry_API::get_api_base_url()<\/code> (HTTPS-only allowlist, blocks private \/ reserved IPs). Previously the SSE proxy, tracking, public localization, and admin tracking-token fetch read the option raw, so a direct DB write of a malicious URL would have been honoured. Tightens defense-in-depth around SSRF.<\/li>\n<li>Hardening: 4 admin AJAX endpoints (<code>anytry_start_trial<\/code>, <code>anytry_send_magic_link<\/code>, <code>anytry_fetch_key_by_email<\/code>, <code>anytry_get_status<\/code>) lowered from <code>manage_options<\/code> to <code>manage_woocommerce<\/code> so they match the Settings-page capability. Shop Manager users could see the buttons but the AJAX returned 403 on click \u2014 now the menu item and the action are gated by the same capability.<\/li>\n<li>Hardening: multisite-network-aware uninstall. On network-active deletions the cleanup routine now loops every site (<code>get_sites()<\/code> + <code>switch_to_blog()<\/code>) so subsite options, log tables, post meta, HPOS order meta, transients, and <code>uploads\/anytry\/*<\/code> files are removed across the whole network instead of just the primary blog.<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Hardening: cross-plugin survival via IIFE try\/catch wrap \u2014 AnyTry now keeps initializing even when other plugins throw cascade pageerrors (<code>$ is not a function<\/code>, <code>addEventListener on null<\/code>, etc.).<\/li>\n<li>Hardening: block-theme compatibility \u2014 JS-side single-product trigger fallback when <code>woocommerce_after_add_to_cart_button<\/code> PHP hook is unavailable (Twenty Twenty-Four \/ Twenty Twenty-Five and other block themes).<\/li>\n<li>Hardening: Async JavaScript \/ page-optimizer compatibility \u2014 companion script handles (<code>anytry-script-js-before<\/code> + <code>anytry-script-js-extra<\/code>) carry <code>data-no-optimize=\"1\"<\/code> to prevent base64 data: URI rewrite from breaking init order.<\/li>\n<li>Hardening: listing-pill clone identity \u2014 pill clones now carry <code>.anytry-button<\/code> class + <code>data-anytry=\"trigger\"<\/code> attribute so third-party quickview modules (IQIT, TvCMS) don't double-open their own modals.<\/li>\n<li>Hardening: hostile-CSS defense \u2014 pill clones inline <code>display: inline-flex !important<\/code> to beat <code>[class*=\"anytry-\"]{display:none!important}<\/code> rules from hostile theme bundles.<\/li>\n<li>Hardening: infinite-scroll memory leak fix \u2014 per-card <code>MutationObserver<\/code> now uses a <code>WeakMap<\/code> registry + <code>target.isConnected<\/code> self-disconnect so observers clean up when product cards leave the DOM.<\/li>\n<li>Bug fix: admin color settings now ALWAYS take effect \u2014 <code>:root<\/code> block always emits all 8 CSS variables (was: empty when defaults matched, leaving 21 of 47 <code>var(--at-*)<\/code> refs undefined and rendering as initial). Settings always reflect on the storefront, even when other values match defaults.<\/li>\n<li>Bug fix: 0px corner radius now applies \u2014 <code>empty('0')<\/code> returned true in PHP, silently rejecting operator-set 0px radius and stuck on default 2px. Now uses explicit <code>absint()<\/code> so 0 wins.<\/li>\n<li>Bug fix: button-background hex normalization \u2014 <code>#000<\/code> (3-digit) and <code>#000000<\/code> (6-digit) are now treated as the same color, so the button-background override fires correctly regardless of which hex form the operator picks.<\/li>\n<li>Bug fix: minimize-aware repaint guard \u2014 minimized modal no longer disappears when a background generation completes.<\/li>\n<li>Bug fix: HEIC race \u2014 <code>_fileConverting<\/code> flag prevents a double-click during HEIC convert from kicking off two generations.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial public release.<\/li>\n<li>AI Virtual Try-On powered by generative AI (connects to the AnyTry API).<\/li>\n<li>AI Size Advisor with simple and full quiz modes.<\/li>\n<li>Conversion tracking (WooCommerce orders + AnyTry API attribution).<\/li>\n<li>Admin panel with CSS customization, button styles, and quiz modes.<\/li>\n<li>Full PL \/ EN \/ DE \/ UK localization.<\/li>\n<li>WooCommerce HPOS compatibility.<\/li>\n<li>WooCommerce Blocks checkout support.<\/li>\n<\/ul>","raw_excerpt":"AI-powered virtual try-on for WooCommerce. Let customers see how clothes look on them before buying \u2014 powered by generative AI.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/306734","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=306734"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/piezak"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=306734"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=306734"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=306734"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=306734"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=306734"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=306734"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}