{"id":385428,"date":"2026-10-14T18:46:50","date_gmt":"2026-10-14T18:46:50","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/rotozoom-product-filter\/"},"modified":"2026-10-14T18:46:38","modified_gmt":"2026-10-14T18:46:38","slug":"rotozoom-product-filter","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/rotozoom-product-filter\/","author":23534051,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.43","stable_tag":"1.0.43","tested":"7.1.3","requires":"6.9","requires_php":"8.0","requires_plugins":null,"header_name":"Rotozoom Product Filter","header_author":"Rotozoom","header_description":"Fast AJAX product filtering for WooCommerce \u2014 filter by attribute, price, stock, rating and more with no page reloads.","assets_banners_color":"5f52a3","last_updated":"2026-10-14 18:46:38","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/rotozoom.com\/plugins\/product-filter","header_author_uri":"https:\/\/rotozoom.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":59,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.43":{"tag":"1.0.43","author":"rotozoom","date":"2026-10-14 18:46:38","revision":3746966}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3746965,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3746965,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3746965,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3746965,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3746965,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{"blueprint.json":{"filename":"blueprint.json","revision":3746966,"resolution":false,"location":"assets","locale":"","contents":"{\"$schema\":\"https:\\\/\\\/playground.wordpress.net\\\/blueprint-schema.json\",\"landingPage\":\"\\\/shop\\\/\",\"login\":true,\"preferredVersions\":{\"php\":\"8.2\",\"wp\":\"7.1\"},\"phpExtensionBundles\":[\"kitchen-sink\"],\"features\":{\"networking\":true},\"steps\":[{\"step\":\"installPlugin\",\"pluginData\":{\"resource\":\"wordpress.org\\\/plugins\",\"slug\":\"woocommerce\"},\"options\":{\"activate\":true}},{\"step\":\"installPlugin\",\"pluginData\":{\"resource\":\"wordpress.org\\\/plugins\",\"slug\":\"rotozoom-product-filter\"},\"options\":{\"activate\":true}},{\"step\":\"installTheme\",\"themeData\":{\"resource\":\"wordpress.org\\\/themes\",\"slug\":\"storefront\"},\"options\":{\"activate\":true}},{\"step\":\"setSiteOptions\",\"options\":{\"blogname\":\"Rotozoom Demo Store\",\"blogdescription\":\"Live preview \\u2014 Rotozoom Product Filter\",\"permalink_structure\":\"\\\/%postname%\\\/\",\"woocommerce_currency\":\"EUR\",\"woocommerce_default_country\":\"DE\",\"woocommerce_onboarding_profile\":{\"skipped\":true},\"woocommerce_task_list_hidden\":\"yes\",\"woocommerce_coming_soon\":\"no\",\"woocommerce_store_pages_only\":\"no\",\"woocommerce_allow_tracking\":\"no\"}},{\"step\":\"mkdir\",\"path\":\"\\\/wordpress\\\/wp-content\\\/mu-plugins\"},{\"step\":\"writeFile\",\"path\":\"\\\/wordpress\\\/wp-content\\\/mu-plugins\\\/rotozoom-demo-store.php\",\"data\":\"<?php\\n\\\/**\\n * Rotozoom demo store \\u2014 Playground only.\\n *\\n * Storefront paginates the shop at 12, while the filter toolbar offers 32\\\/64\\\/128.\\n * One page of the whole 17-product catalogue makes a filter click a visible change\\n * instead of a pagination artefact, and keeps the toolbar honest.\\n *\\\/\\nadd_filter( 'loop_shop_per_page', static function () { return 32; }, 99 );\\n\\n\\\/**\\n * Playground stays busy for ~25 s after the shop first paints (OPFS save), and its\\n * own service worker gives up on any request it has been holding (sw.js: const\\n * Ls=25e3). Measured from the moment the browser sends it, that failure lands at\\n * 27.0 s - 26 957 to 27 032 ms across four boots - the worker's 25 s timer\\n * plus the ~2 s it takes to start while the main thread is busy. A filter click in\\n * that window cannot succeed on the first try whatever ceiling we set.\\n *\\n * So the ceiling's only job here is to LOSE that race, leaving the failure as a\\n * network error (status 0) - the one thing 1.0.42 retries by itself, 800 ms later,\\n * by which time the busy window is over. jQuery's own timer is starved by the same\\n * ~2 s, which puts the crossover at ~25 100 ms, not at 25 000.\\n *\\n * Measured on this blueprint with 1.0.42, clicking at +10 s after the first paint:\\n *   20 000 (the shipped default) aborts at 22 005 ms -> \\\"The request took too long.\\\"\\n *                                                       over an empty grid\\n *   25 000                       aborts at 26 938 ms -> same banner, ~90 ms before\\n *                                                       the network failure\\n *   30 000                       retries -> 17 -> 4 products, no banner (31.3 s \\\/ 31.0 s)\\n *   60 000                       retries -> 17 -> 4 products, no banner (31.3 s)\\n * 30 000 and 60 000 are indistinguishable in outcome; 60 000 is kept because the two\\n * failure modes are not symmetric. Too high costs a longer skeleton in a preview if\\n * Playground ever stops failing the request itself; too low costs every .org visitor\\n * an error box on the first click, and a timeout is deliberately never retried.\\n *\\n * Preview-only: a real shop keeps the 20 s default, this file ships with nothing.\\n *\\\/\\nadd_filter( 'rotozoom_filter_ajax_timeout', static function () { return 60000; }, 99 );\\n\"},{\"step\":\"runPHP\",\"code\":\"<?php\\nrequire_once '\\\/wordpress\\\/wp-load.php';\\n\\n\\\/\\\/ WooCommerce's first-run wizard would hijack the landing page.\\ndelete_transient( '_wc_activation_redirect' );\\nupdate_option( 'woocommerce_admin_notices', array() );\\n\\n\\\/\\\/ Shop \\\/ Cart \\\/ Checkout \\\/ My account. Idempotent in WooCommerce.\\nif ( class_exists( 'WC_Install' ) ) {\\n\\tWC_Install::create_pages();\\n}\\n\\n\\\/\\\/ Global attributes must exist BEFORE the WXR import: the sample catalogue assigns\\n\\\/\\\/ pa_color \\\/ pa_size terms, and wp_set_object_terms() silently drops a taxonomy that\\n\\\/\\\/ is not registered. WooCommerce registers pa_* from this table at init, so creating\\n\\\/\\\/ them here makes them live for the import step's own request.\\n$attrs = array(\\n\\t'color' => 'Color',\\n\\t'size'  => 'Size',\\n);\\nforeach ( $attrs as $slug => $label ) {\\n\\tif ( taxonomy_exists( 'pa_' . $slug ) ) {\\n\\t\\tcontinue;\\n\\t}\\n\\twc_create_attribute( array(\\n\\t\\t'name'         => $label,\\n\\t\\t'slug'         => $slug,\\n\\t\\t'type'         => 'select',\\n\\t\\t'order_by'     => 'menu_order',\\n\\t\\t'has_archives' => false,\\n\\t) );\\n}\\ndelete_transient( 'wc_attribute_taxonomies' );\\n\\n\\\/\\\/ --- Rotozoom Product Filter -------------------------------------------------\\n\\\/\\\/ Every one of these has a code-side default; they are set explicitly so the demo\\n\\\/\\\/ is identical on every boot and shows the widest sidebar.\\nupdate_option( 'rotozoom_filter_sections', array(\\n\\t'sorting'      => true,\\n\\t'price'        => true,\\n\\t'categories'   => true,\\n\\t'brands'       => true,\\n\\t'availability' => true,\\n\\t'special'      => true,\\n\\t'rating'       => true,\\n\\t'attributes'   => true,\\n) );\\nupdate_option( 'rotozoom_filter_display', array(\\n\\t'default_state'    => 'unfolded',\\n\\t'sections'         => array(),\\n\\t'cache_enabled'    => false,\\n\\t'attr_logic_map'   => array(),\\n\\t'per_page_options' => '',\\n) );\\n\\\/\\\/ \\\"Color\\\" would auto-render as swatches; checkboxes show the per-term product\\n\\\/\\\/ counts, which is what makes the filter legible in a 30-second demo.\\nupdate_option( 'rotozoom_filter_attribute_config', array(\\n\\t'pa_color' => 'checkboxes',\\n\\t'pa_size'  => 'checkboxes',\\n) );\\nupdate_option( 'rotozoom_filter_attribute_order', array( 'pa_color', 'pa_size' ) );\\nupdate_option( 'rotozoom_filter_section_order', array( 'attributes', 'categories', 'price', 'availability', 'special', 'rating' ) );\\n\"},{\"step\":\"importWxr\",\"file\":{\"resource\":\"vfs\",\"path\":\"\\\/wordpress\\\/wp-content\\\/plugins\\\/woocommerce\\\/sample-data\\\/sample_products.xml\"}},{\"step\":\"runPHP\",\"code\":\"<?php\\nrequire_once '\\\/wordpress\\\/wp-load.php';\\n\\n\\\/\\\/ Term counts drive the sidebar: Rotozoom Product Filter asks get_terms() with\\n\\\/\\\/ hide_empty => true, so a term whose count column is stale renders as nothing.\\nforeach ( array( 'product_cat', 'product_tag', 'pa_color', 'pa_size' ) as $tax ) {\\n\\tif ( ! taxonomy_exists( $tax ) ) {\\n\\t\\tcontinue;\\n\\t}\\n\\t$ids = get_terms( array( 'taxonomy' => $tax, 'hide_empty' => false, 'fields' => 'ids' ) );\\n\\tif ( ! is_wp_error( $ids ) && $ids ) {\\n\\t\\twp_update_term_count_now( $ids, $tax );\\n\\t}\\n}\\n\\n\\\/\\\/ The filter toolbar's \\\"Show:\\\" control reads posts_per_page, while Storefront's shop\\n\\\/\\\/ loop ignores it (storefront_products_per_page returns 12) \\u2014 so both are set to the\\n\\\/\\\/ same 32, the first free-tier page size, and the toolbar cannot contradict the grid.\\nupdate_option( 'posts_per_page', 32 );\\nupdate_option( 'woocommerce_catalog_columns', 3 );\\n\\n\\\/\\\/ Storefront's own shop sidebar would sit next to ours; the plugin's layout is the\\n\\\/\\\/ point of the demo, so the theme's widget column stays empty.\\nupdate_option( 'sidebars_widgets', array( 'wp_inactive_widgets' => array() ) );\\n\\n\\\/\\\/ WooCommerce >= 9.1 hides a brand-new store behind a \\\"coming soon\\\" page.\\nupdate_option( 'woocommerce_coming_soon', 'no' );\\n\\nwc_update_product_lookup_tables();\\nflush_rewrite_rules( false );\\n\"}]}"}},"all_blocks":[],"tagged_versions":["1.0.43"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3746965,"resolution":"1","location":"assets","locale":"","width":788,"height":860},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3746965,"resolution":"2","location":"assets","locale":"","width":1200,"height":1029}},"screenshots":{"1":"Front-end filter sidebar on the shop page \u2014 sorting, price range, categories, availability and attribute groups filter the product grid instantly with no page reload.","2":"Admin attribute configuration \u2014 choose a display type (auto, slider, swatches, checkboxes, radio) per attribute and drag to reorder them."}},"plugin_section":[],"plugin_tags":[5861,270234,286806,6033,158225],"plugin_category":[],"plugin_contributors":[285119],"plugin_business_model":[],"class_list":["post-385428","plugin","type-plugin","status-publish","hentry","plugin_tags-ajax-filter","plugin_tags-attribute-filter","plugin_tags-catalog-filter","plugin_tags-product-filter","plugin_tags-shop-filter","plugin_contributors-rotozoom","plugin_committers-rotozoom"],"banners":{"banner":"https:\/\/ps.w.org\/rotozoom-product-filter\/assets\/banner-772x250.png?rev=3746965","banner_2x":"https:\/\/ps.w.org\/rotozoom-product-filter\/assets\/banner-1544x500.png?rev=3746965","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/rotozoom-product-filter\/assets\/icon.svg?rev=3746965","icon":"https:\/\/ps.w.org\/rotozoom-product-filter\/assets\/icon.svg?rev=3746965","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/rotozoom-product-filter\/assets\/screenshot-1.png?rev=3746965","caption":"Front-end filter sidebar on the shop page \u2014 sorting, price range, categories, availability and attribute groups filter the product grid instantly with no page reload."},{"src":"https:\/\/ps.w.org\/rotozoom-product-filter\/assets\/screenshot-2.png?rev=3746965","caption":"Admin attribute configuration \u2014 choose a display type (auto, slider, swatches, checkboxes, radio) per attribute and drag to reorder them."}],"raw_content":"<!--section=description-->\n<p>Rotozoom Product Filter adds a fast, modern filtering sidebar to your WooCommerce shop, category and search pages. Customers narrow down products instantly \u2014 without full page reloads \u2014 using attributes, price ranges, stock status, ratings, on-sale and more.<\/p>\n\n<p>The plugin renders results through your active theme's own product loop, so filtered results look identical to your normal shop pages on classic themes, third-party themes and block (FSE) themes alike.<\/p>\n\n<h4>Features<\/h4>\n\n<ul>\n<li>AJAX filtering with no page reload<\/li>\n<li>Filter by product attributes (color, size, socket, wattage \u2014 any WooCommerce attribute)<\/li>\n<li>Price range slider<\/li>\n<li>Stock status, on-sale, new, rating and review filters<\/li>\n<li>Per-attribute display types: checkboxes, radio, color swatches, or numeric slider<\/li>\n<li>Drag &amp; drop to order attributes in the admin<\/li>\n<li>Sortable sections and collapsible groups<\/li>\n<li>Mobile filter drawer<\/li>\n<li>Works with classic, third-party and block (FSE) themes<\/li>\n<li>Translation-ready<\/li>\n<\/ul>\n\n<h4>Shortcodes<\/h4>\n\n<ul>\n<li><code>[rotozoom_filter]<\/code> \u2014 renders the filter sidebar and a filterable product grid on any page or post<\/li>\n<li><p><code>[rotozoom_filter_bar]<\/code> \u2014 renders the per-page selector on its own, for authors who want it somewhere other than above the grid (use together with <code>[rotozoom_filter bar=\"0\"]<\/code>)<\/p>\n\n<p>[rotozoom_filter] accepts:<\/p><\/li>\n<li><p><code>category<\/code> \u2014 limit the grid to one product category slug, e.g. <code>[rotozoom_filter category=\"led-panels\"]<\/code><\/p><\/li>\n<li><code>per_page<\/code> \u2014 products per page (default: your shop's WooCommerce products per page)<\/li>\n<li><code>columns<\/code> \u2014 grid columns (default: your theme's WooCommerce setting)<\/li>\n<li><code>orderby<\/code> \u2014 <code>menu_order<\/code>, <code>popularity<\/code>, <code>rating<\/code>, <code>date<\/code>, <code>price<\/code> or <code>price-desc<\/code><\/li>\n<li><code>sidebar<\/code> \u2014 <code>0<\/code> to render the grid without the filter sidebar<\/li>\n<li><code>bar<\/code> \u2014 <code>0<\/code> to hide the built-in toolbar<\/li>\n<\/ul>\n\n<h3>External services<\/h3>\n\n<p>This plugin does not connect to, send data to, or load any code from external services. It runs entirely on your own site.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>rotozoom-product-filter<\/code> folder to <code>\/wp-content\/plugins\/<\/code>, or install it through the WordPress Plugins screen.<\/li>\n<li>Activate the plugin through the <strong>Plugins<\/strong> screen in WordPress.<\/li>\n<li>Make sure WooCommerce is installed and active.<\/li>\n<li>Open <strong>Product Filter<\/strong> in the admin menu to choose which attributes and sections to show.<\/li>\n<li>The filter appears automatically on shop, category and search pages, or place the <code>[rotozoom_filter]<\/code> shortcode on any page.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20it%20require%20woocommerce%3F\"><h3>Does it require WooCommerce?<\/h3><\/dt>\n<dd><p>Yes. Rotozoom Product Filter extends WooCommerce, and WordPress asks you to install and activate WooCommerce first.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20block%20%2F%20full%20site%20editing%20themes%3F\"><h3>Does it work with block \/ Full Site Editing themes?<\/h3><\/dt>\n<dd><p>Yes. Results are rendered through your theme's native product loop, so block themes (for example Twenty Twenty-Four) display filtered products with their normal styling.<\/p><\/dd>\n<dt id=\"does%20it%20send%20any%20data%20to%20external%20servers%3F\"><h3>Does it send any data to external servers?<\/h3><\/dt>\n<dd><p>No. The plugin is fully self-contained and makes no external network requests.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.43<\/h4>\n\n<ul>\n<li>First release on WordPress.org.<\/li>\n<li>Several values of one attribute can be ticked together (any of them matches), and every value shows how many products it would add.<\/li>\n<li>The price presets follow the shop's own prices.<\/li>\n<li>Filtering and pagination work on shop addresses that live in the query string (<code>?post_type=product<\/code>, a product search, plain permalinks).<\/li>\n<li>A filter request that drops at the network level is retried once; counts that cannot be refreshed are dimmed and every option stays clickable.<\/li>\n<li>The AJAX request timeout can be changed with the <code>rotozoom_filter_ajax_timeout<\/code> filter (20 seconds by default, 1 to 600 seconds).<\/li>\n<\/ul>","raw_excerpt":"Fast AJAX product filtering for WooCommerce \u2014 filter by attribute, price, stock, rating and more with no page reloads.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/385428","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=385428"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/rotozoom"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=385428"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=385428"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=385428"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=385428"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=385428"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=385428"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}