{"id":379960,"date":"2026-10-09T01:12:47","date_gmt":"2026-10-09T01:12:47","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/product-spin-for-woocommerce\/"},"modified":"2026-10-09T01:12:34","modified_gmt":"2026-10-09T01:12:34","slug":"sonicpixel-product-spin","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/sonicpixel-product-spin\/","author":6699588,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.2.5","stable_tag":"1.2.5","tested":"7.1.3","requires":"6.0","requires_php":"7.4","requires_plugins":null,"header_name":"Sonic Pixel Product Spin for WooCommerce","header_author":"Sonic Pixel","header_description":"Self-hosted 360\u00b0 product spin viewer. Attach ordered photos from the media library; the standard WooCommerce gallery is never replaced.","assets_banners_color":"152548","last_updated":"2026-10-09 01:12:34","external_support_url":"","external_repository_url":"","donate_link":"https:\/\/ko-fi.com\/maikunari","header_plugin_uri":"","header_author_uri":"https:\/\/sonicpixel.io","rating":0,"author_block_rating":0,"active_installs":0,"downloads":94,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.2.5":{"tag":"1.2.5","author":"maikunari","date":"2026-10-09 01:12:34","revision":3735753}},"upgrade_notice":{"1.2.5":"<p>Renamed. Deactivate the old Product Spin for WooCommerce, activate this one, then remove the old folder by FTP or file manager, not Plugins \u2192 Delete (its uninstall deletes your spin data). Replace [product_spin] shortcodes with [sppfw_product_spin].<\/p>","1.2.4":"<p>Readiness fixes for wordpress.org (Tested up to 7.1, dropped Plugin URI, added an icon) plus small internal cleanups. No behavior change for existing sites.<\/p>","1.2.3":"<p>Follow-up to 1.2.2: on a multi-attribute variable product the gallery could still slide off the spin on page load. Recommended for anyone running 1.2.2 with gallery placement.<\/p>","1.2.2":"<p>Fixes gallery placement on variable products (the spin no longer flips to the featured image on load) and the black lightbox when zooming from the spin slide.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3735753,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3735753,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3735753,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3735753,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.2.5"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3737657,"resolution":"1","location":"assets","locale":"","width":1280,"height":1030},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3737657,"resolution":"2","location":"assets","locale":"","width":1440,"height":735},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3737657,"resolution":"3","location":"assets","locale":"","width":1440,"height":790},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3737657,"resolution":"4","location":"assets","locale":"","width":1440,"height":580},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3737657,"resolution":"5","location":"assets","locale":"","width":1440,"height":1010},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3737657,"resolution":"6","location":"assets","locale":"","width":1280,"height":828}},"screenshots":{"1":"Product editor \u2014 360\u00b0 Spin metabox with frame thumbnails, placement, and shortcode.","2":"Frontend spin on a product page (below-summary or tab), gallery otherwise unchanged.","3":"Extra \u201c360\u00b0 View\u201d product tab.","4":"First gallery slide with a 360\u00b0 thumbnail badge.","5":"Catalog 360\u00b0 badge on shop thumbnails.","6":"Media Library \u201cSpin frames\u201d filter."}},"plugin_section":[],"plugin_tags":[745,233,279607,58638,286],"plugin_category":[45],"plugin_contributors":[248169],"plugin_business_model":[],"class_list":["post-379960","plugin","type-plugin","status-publish","hentry","plugin_tags-745","plugin_tags-media-library","plugin_tags-product-spin","plugin_tags-product-viewer","plugin_tags-woocommerce","plugin_category-ecommerce","plugin_contributors-maikunari","plugin_committers-maikunari"],"banners":{"banner":"https:\/\/ps.w.org\/sonicpixel-product-spin\/assets\/banner-772x250.png?rev=3735753","banner_2x":"https:\/\/ps.w.org\/sonicpixel-product-spin\/assets\/banner-1544x500.png?rev=3735753","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/sonicpixel-product-spin\/assets\/icon-128x128.png?rev=3735753","icon_2x":"https:\/\/ps.w.org\/sonicpixel-product-spin\/assets\/icon-256x256.png?rev=3735753","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/sonicpixel-product-spin\/assets\/screenshot-1.png?rev=3737657","caption":"Product editor \u2014 360\u00b0 Spin metabox with frame thumbnails, placement, and shortcode."},{"src":"https:\/\/ps.w.org\/sonicpixel-product-spin\/assets\/screenshot-2.png?rev=3737657","caption":"Frontend spin on a product page (below-summary or tab), gallery otherwise unchanged."},{"src":"https:\/\/ps.w.org\/sonicpixel-product-spin\/assets\/screenshot-3.png?rev=3737657","caption":"Extra \u201c360\u00b0 View\u201d product tab."},{"src":"https:\/\/ps.w.org\/sonicpixel-product-spin\/assets\/screenshot-4.png?rev=3737657","caption":"First gallery slide with a 360\u00b0 thumbnail badge."},{"src":"https:\/\/ps.w.org\/sonicpixel-product-spin\/assets\/screenshot-5.png?rev=3737657","caption":"Catalog 360\u00b0 badge on shop thumbnails."},{"src":"https:\/\/ps.w.org\/sonicpixel-product-spin\/assets\/screenshot-6.png?rev=3737657","caption":"Media Library \u201cSpin frames\u201d filter."}],"raw_content":"<!--section=description-->\n<p><strong>Sonic Pixel Product Spin for WooCommerce<\/strong> lets a shop manager attach an ordered set of photos to a product and show them as a 360\u00b0 spin on the product page. Frames live in the WordPress media library and are served by your own site. There is no third-party CDN, no subscription, and no remote service that can shut down.<\/p>\n\n<p>The plugin never replaces the WooCommerce product gallery. You can show the spin via a <code>[sppfw_product_spin]<\/code> shortcode, an extra product tab, a section below the product summary, or as the <strong>first gallery slide<\/strong> (the theme keeps thumbnails, zoom, and lightbox). Shop and category pages can show a small 360\u00b0 badge on products that have frames \u2014 the viewer itself is not loaded on archives.<\/p>\n\n<h4>Key Features<\/h4>\n\n<ul>\n<li><strong>Self-hosted frames<\/strong> \u2014 ordinary media-library attachments, stored under <code>wp-content\/uploads\/<\/code><\/li>\n<li><strong>Does not replace the gallery<\/strong> \u2014 optional first-slide injection; thumbnails, lightbox, zoom, and variation images stay with the theme<\/li>\n<li><strong>Placements<\/strong> \u2014 shortcode, extra tab, below-summary, or first gallery slide (falls back to below-summary if the theme gallery is not recognised)<\/li>\n<li><strong>Catalog 360\u00b0 badge<\/strong> \u2014 presentational badge on shop\/category thumbnails; opt out under WooCommerce \u2192 Settings \u2192 Products<\/li>\n<li><strong>Drag, touch, and keyboard<\/strong> \u2014 Pointer Events for mouse and touch, inertia after a flick, arrow keys for accessibility, optional autoplay<\/li>\n<li><strong>Lazy loading<\/strong> \u2014 remaining frames load on first interaction or when the viewer scrolls into view<\/li>\n<li><strong>Simple product editor<\/strong> \u2014 media-library multi-select, drag-to-reorder thumbnails, placement radios, autoplay checkbox<\/li>\n<li><strong>Library hygiene<\/strong> \u2014 spin frames are tagged and hidden from the general media library by default, with a \u201cSpin frames\u201d filter to reach them<\/li>\n<li><strong>Organized uploads<\/strong> \u2014 new frames uploaded from the product metabox go to <code>uploads\/product-spins\/product-{id}\/<\/code><\/li>\n<li><strong>Conditional assets<\/strong> \u2014 viewer CSS and JS enqueue only on pages that actually render a spin; archives never load the viewer<\/li>\n<\/ul>\n\n<h4>How to use<\/h4>\n\n<ol>\n<li>Edit a WooCommerce product.<\/li>\n<li>In the <strong>360\u00b0 Spin<\/strong> box, click <strong>Add \/ Edit frames<\/strong> and select 24\u201372 photos shot in order around the product. Frame 1 is the resting view.<\/li>\n<li>Drag thumbnails to reorder if needed.<\/li>\n<li>Choose a placement (None \/ Extra tab \/ Below product summary \/ First gallery slide) and optionally enable autoplay.<\/li>\n<li>Update the product. You can also paste the shortcode <code>[sppfw_product_spin]<\/code> into any page or product description.<\/li>\n<li>Optionally turn off the catalog 360\u00b0 badge under WooCommerce \u2192 Settings \u2192 Products.<\/li>\n<\/ol>\n\n<h4>How to shoot frames<\/h4>\n\n<ul>\n<li>Mount the camera (or the product) so the framing stays consistent.<\/li>\n<li>Rotate the product in even steps. <strong>24 frames (15\u00b0)<\/strong> is the practical minimum; <strong>36 frames (10\u00b0)<\/strong> is the usual sweet spot; <strong>72 frames (5\u00b0)<\/strong> is very smooth but heavier.<\/li>\n<li>Keep lighting and background constant. Export JPEGs; WordPress will create intermediate sizes.<\/li>\n<\/ul>\n\n<h4>Requirements<\/h4>\n\n<ul>\n<li>WordPress 6.0 or higher<\/li>\n<li>WooCommerce 7.0 or higher<\/li>\n<li>PHP 7.4 or higher<\/li>\n<\/ul>\n\n<h3>Additional Information<\/h3>\n\n<h4>Privacy<\/h4>\n\n<p>This plugin does not collect, store, or transmit personal data. It stores product meta (frame attachment IDs, placement, autoplay) on your site.<\/p>\n\n<h4>Credits<\/h4>\n\n<p>Developed by Mike Sewell at <a href=\"https:\/\/sonicpixel.io\/\">SonicPixel<\/a>.<\/p>\n\n<h4>License<\/h4>\n\n<p>This plugin is licensed under the GPL v2 or later.<\/p>\n\n<!--section=installation-->\n<h4>Automatic Installation<\/h4>\n\n<ol>\n<li>Log in to your WordPress dashboard.<\/li>\n<li>Navigate to Plugins \u2192 Add New.<\/li>\n<li>Search for \u201cSonic Pixel Product Spin for WooCommerce\u201d.<\/li>\n<li>Click Install Now, then Activate.<\/li>\n<li>Edit a product and use the <strong>360\u00b0 Spin<\/strong> box.<\/li>\n<\/ol>\n\n<h4>Manual Installation<\/h4>\n\n<ol>\n<li>Upload the <code>sonicpixel-product-spin<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate the plugin through the Plugins menu.<\/li>\n<li>Edit a product and use the <strong>360\u00b0 Spin<\/strong> box.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20replace%20my%20product%20gallery%3F\"><h3>Does this replace my product gallery?<\/h3><\/dt>\n<dd><p>No. The gallery is never swapped out for a custom viewer. <strong>First gallery slide<\/strong> inserts the spin as an extra first slide and leaves the theme\u2019s thumbnails, lightbox, zoom, and variation-image swapping in place. If the theme does not use the standard WooCommerce gallery container, that placement falls back to below the product summary instead of rendering nothing.<\/p><\/dd>\n<dt id=\"will%20shop%20pages%20load%20the%20360%20viewer%3F\"><h3>Will shop pages load the 360 viewer?<\/h3><\/dt>\n<dd><p>No. Archives show a small 360\u00b0 badge on products that have frames. The viewer CSS and JavaScript are not enqueued on shop or category pages. Turn the badge off under WooCommerce \u2192 Settings \u2192 Products if every product has a spin.<\/p><\/dd>\n<dt id=\"where%20are%20the%20frames%20stored%3F\"><h3>Where are the frames stored?<\/h3><\/dt>\n<dd><p>In your site\u2019s media library, as normal attachments. The plugin stores attachment IDs in product meta and resolves URLs at render time. Nothing is hosted by a third party.<\/p><\/dd>\n<dt id=\"how%20many%20frames%20do%20i%20need%20for%20a%20full%20360%C2%B0%3F\"><h3>How many frames do I need for a full 360\u00b0?<\/h3><\/dt>\n<dd><p>Any count of two or more will spin fully \u2014 one drag across the viewer maps to the whole set. 24 frames is the practical minimum so motion does not feel steppy; 36 is the industry-standard sweet spot; 72 is very smooth but doubles the payload.<\/p><\/dd>\n<dt id=\"will%20this%20work%20with%20my%20custom%20theme%3F\"><h3>Will this work with my custom theme?<\/h3><\/dt>\n<dd><p>Tab, below-summary, and shortcode work as long as the theme does not strip shortcodes or WooCommerce tab filters. First-gallery-slide placement targets <code>.woocommerce-product-gallery<\/code>. Storefront and Astra keep the classic FlexSlider wrapper, so the spin is a real first slide with a 360\u00b0 thumbnail badge. Blocksy keeps the gallery container but rebuilds slides in its own Flexy slider from attachment IDs \u2014 the spin is shown above that slider in the gallery column rather than as a Flexy slide. A bespoke product template that does not output the container, or that does not run <code>woocommerce_single_product_image_thumbnail_html<\/code>, gets the below-summary fallback.<\/p><\/dd>\n<dt id=\"are%20viewer%20assets%20loaded%20on%20every%20product%3F\"><h3>Are viewer assets loaded on every product?<\/h3><\/dt>\n<dd><p>No. Viewer CSS and JavaScript enqueue only when a spin is actually rendered (product with a placement, or a page that contains the shortcode). Catalog pages load only a tiny badge stylesheet, and only when the badge is enabled.<\/p><\/dd>\n<dt id=\"can%20i%20keep%20using%20the%20shortcode%20if%20i%20choose%20%E2%80%9Cnone%E2%80%9D%20for%20placement%3F\"><h3>Can I keep using the shortcode if I choose \u201cNone\u201d for placement?<\/h3><\/dt>\n<dd><p>Yes. Placement only controls the automatic product-page output. <code>[sppfw_product_spin]<\/code> always works when the product has frames.<\/p><\/dd>\n<dt id=\"do%20spin%20frames%20clutter%20the%20media%20library%3F\"><h3>Do spin frames clutter the media library?<\/h3><\/dt>\n<dd><p>By default they are hidden from the general library and from the media modal, except inside this plugin\u2019s own frame picker. A <strong>Spin frames<\/strong> filter on the Media Library lists them on purpose. This can be disabled with the <code>psfw_hide_frames_from_library<\/code> filter.<\/p><\/dd>\n<dt id=\"does%20this%20work%20with%20variable%20products%3F\"><h3>Does this work with variable products?<\/h3><\/dt>\n<dd><p>v1 attaches one spin per product, not per variation.<\/p><\/dd>\n<dt id=\"is%20this%20compatible%20with%20high-performance%20order%20storage%20%28hpos%29%3F\"><h3>Is this compatible with High-Performance Order Storage (HPOS)?<\/h3><\/dt>\n<dd><p>Yes. The plugin declares HPOS compatibility. It does not read or write orders.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<p>Older entries live in <code>changelog.txt<\/code>.<\/p>\n\n<h4>1.2.5<\/h4>\n\n<ul>\n<li>Renamed to \"Sonic Pixel Product Spin for WooCommerce\" (wordpress.org slug <code>sonicpixel-product-spin<\/code>) at the plugin review team's request. The plugin folder and main file are now <code>sonicpixel-product-spin\/sonicpixel-product-spin.php<\/code> and the text domain is <code>sonicpixel-product-spin<\/code>. Sites running the old Product Spin for WooCommerce: deactivate it, activate the renamed plugin (both cannot be active together), then remove the old <code>product-spin-for-woocommerce<\/code> folder with FTP or a file manager. Do not use Plugins \u2192 Delete on the old plugin: its uninstall deletes the spin frames and settings the renamed plugin uses. Frame data and settings otherwise carry over.<\/li>\n<li>The shortcode is now <code>[sppfw_product_spin]<\/code>; the unprefixed <code>[product_spin]<\/code> is no longer registered. Replace it in any page or product description that used it.<\/li>\n<li>Prefixed the script and style handles (<code>sppfw-product-spin<\/code>, <code>sppfw-product-spin-archive<\/code>).<\/li>\n<\/ul>\n\n<h4>1.2.4<\/h4>\n\n<ul>\n<li>Bumped <code>Tested up to: 7.1<\/code> and <code>WC tested up to: 11.1<\/code> \u2014 re-verified with the repo's own 57-check Playwright suite on WP 7.1.2 + WooCommerce 11.1.2, WP_DEBUG on, zero PHP notices.<\/li>\n<li>Removed the <code>Plugin URI<\/code> header. It duplicated the <code>Author URI<\/code>, and wordpress.org requires a URI unique to the plugin.<\/li>\n<li>Removed the unused <code>Domain Path<\/code> header and <code>load_plugin_textdomain()<\/code> call; translations load automatically for wordpress.org-hosted plugins since WP 4.6.<\/li>\n<li>Prefixed the uninstall script's file-scope globals (<code>$psfw_site_ids<\/code>, <code>$psfw_site_id<\/code>) and swapped its direct <code>$wpdb-&gt;delete()<\/code> call for core's <code>delete_post_meta_by_key()<\/code>.<\/li>\n<li>Dropped a <code>post__not_in<\/code> query arg in favor of skipping the excepted product inside the results loop.<\/li>\n<li>Corrected the GPL license boilerplate to include \"or (at your option) any later version\", matching the GPLv2-or-later header.<\/li>\n<li>Added <code>icon-128x128.png<\/code> \/ <code>icon-256x256.png<\/code>, derived from the existing banner ribbon art.<\/li>\n<li>Fixed stale <code>{product-slug}<\/code> wording in the readme and an admin docblock; uploads have gone to <code>product-{id}<\/code> since 1.1.1.<\/li>\n<\/ul>\n\n<h4>1.2.3<\/h4>\n\n<ul>\n<li>Fixed: on a variable product with more than one attribute, WooCommerce triggers its own \"change\" on the attribute dropdowns while it resolves the form on page load. 1.2.2 counted that as the shopper picking a variation, so the gallery could still move off the spin on load; only a real interaction counts now.<\/li>\n<li>Hardened: the poster's extra attributes are restricted to <code>data-*<\/code>, so a theme calling <code>PSFW_Render::markup()<\/code> with caller-controlled arguments cannot inject an event handler attribute.<\/li>\n<\/ul>\n\n<h4>1.2.2<\/h4>\n\n<ul>\n<li>Fixed: on a variable product, gallery placement showed the spin and then immediately slid to the featured image. WooCommerce runs its variation image code once at page load, and the plugin was treating that as a shopper picking a variation. The gallery now only leaves the spin when a shopper actually chooses a variation that has its own image.<\/li>\n<li>Fixed: clicking the zoom \/ magnifier while the spin slide was showing opened the lightbox on a black slide. WooCommerce reads the large-image data from the first image in a slide, which was the spin poster; the data lived on a hidden image after it and was never read. The poster now carries it, and the hidden hook image is gone.<\/li>\n<li>The spin slide is now protected by a MutationObserver as well as the jQuery patch, so a theme or optimisation plugin that loads WooCommerce's variation script out of order can no longer rewrite the spin's poster, its large-image data, or its thumbnail.<\/li>\n<\/ul>","raw_excerpt":"Self-hosted 360\u00b0 product spin viewer. Attach ordered photos from the media library; the WooCommerce gallery is never replaced.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/379960","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=379960"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/maikunari"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=379960"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=379960"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=379960"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=379960"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=379960"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=379960"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}