AJAX product filter: convenient catalog without page reload
Standard WooCommerce filtering reloads the page on every click and loses selected options. An AJAX filter with a pre-calculated index takes 50 ms, shows the color with a circle, the brand with a logo, and instead of pagination there is a “Show more” button.
COS / KNOWLEDGE BASE
Three years ago, the owner of an online auto parts store called me and said a phrase that I have heard regularly since then: “We have a catalog of fifteen thousand items, and people leave without reaching the right product.” I went to his website, selected the car brand in the filter - the page reloaded. Selected the type of spare part - reboot again. I tried to specify the price range - another reboot, and all previous filters were reset. Three clicks - fifteen seconds of waiting and a complete loss of context. I closed the tab. And I am a person who professionally deals with online stores. What does the average buyer do? That's right, it goes to Wildberries, where filtering works instantly.
This is not the story of one store. This is a systemic problem with WooCommerce, which I see in almost every project where a normal AJAX filter has not yet been installed. The standard filtering mechanism in WooCommerce is extremely simple: you select a parameter, the browser sends a GET request with the new parameters, the server processes the entire request - from parsing the URL to rendering the full HTML page - and returns the result. For each click on the filter, there is a full cycle: querying the database, assembling the template, sending all the HTML back to the browser. And if you have ten thousand products, each with a dozen attributes, and, moreover, the server is not a top one, each such reboot can take two or three seconds. Multiply that by the five to six clicks it takes to narrow down the selection to the products you want, and you get fifteen to twenty seconds of pure wait time. During this time, the buyer has time to change his mind, get distracted, or simply leave.
I studied this problem for a long time - not as a developer, but as a marketer. Because for a marketer, catalog filtering is not a technical detail, but a critical element of the sales funnel. Between “went to the catalog” and “added to cart” there is a filter, and if it works poorly, the funnel flows here. According to the Baymard Institute, forty-two percent of large online retailers lose customers due to inconvenient filtering. Not because of the prices, not because of the assortment - because a person cannot quickly find what he needs. And when I started designing the filtration module for our plugin, I set myself one task: to make sure that the buyer does not even notice that the filter is working. No reboots, no lags, no feeling of “I’m waiting for the computer to think.”
Here's what came of it - and why under the hood it turned out to be much more complicated than it seems at first glance.
Why WooCommerce Standard Filtering is a Pain
To understand why an AJAX filter is not just a nice feature, but a necessity, let's look at what happens when a buyer filters products in standard WooCommerce. Let's say you have an industrial oils store. A buyer enters a catalog, sees eight hundred products, and wants to choose a 5W-30 motor oil from a certain brand. He clicks on the “Filter by attribute” widget, selects “Motor oils” - and the page is completely reloaded. The browser sends a GET request like “?filter_tip-masla=motornoe”, the server processes it, WooCommerce launches WP_Query with meta queries, MySQL iterates through wp_postmeta - a table that can weigh up to a gigabyte on a project with sixteen thousand products - and returns the result in a couple of seconds. The buyer sees, say, three hundred products. Now he wants to select the viscosity. Another click - another reboot, two more seconds. Then the brand - the third reboot. And here’s the most annoying thing: on some themes and configurations, the previous filters are reset upon the next reboot. The buyer starts over.
I've seen this dozens of times on real projects. The store owner invests money in advertising, pays for each click in Yandex.Direct, brings a person to the site - and loses him at the filtering stage. And not because there is no product, but because there is a product, but it is impossible to find it normally. It's like a store where all the goods are piled up in one pile, and the seller answers every question with a delay of three seconds. Would you leave? I would have left.
There's another problem that doesn't get talked about much: WooCommerce's default filtering is very bad for SEO. Each filter option generates a unique URL with GET parameters, and if a search bot starts indexing all these combinations—and there can be ten to the tenth power of combinations with ten attributes with ten values each—you end up with a bloated index, duplicate content, and a diluted crawling budget. For a small store with hundreds of products this is not critical, but for a serious catalog it is a real problem.
Actually, this is why all the major marketplaces - Ozon, Wildberries, Yandex.Market - have long switched to AJAX filtering. When a customer selects an option, the browser sends an asynchronous request to the server, receives only the data—no header, footer, or sidebar—and updates only the portion of the page where the products are shown. No screen flickering, no rebooting, no loss of scrolling. You click and the products change instantly. This is an industry standard, and if your store does not provide it, you are already losing at the user experience level.
But - and here's where things get interesting - simply switching filtering to AJAX is not enough. If the same WP_Query with wp_postmeta joins remains under the hood, you will simply remove the reload, but the response speed will remain the same - the same one and a half to two seconds for each request. The buyer will not see the page reload, but will see a spinner in place of the product list. And the difference between “the page reloads” and “products do not appear” in terms of customer patience is approximately zero. Therefore, when designing our filtering module, I immediately took a radically different approach to storing and retrieving data.
FilterIndex: when fifty milliseconds is not marketing, but reality
The main idea that sets our AJAX filter apart from most solutions on the market is the pre-computed index. It’s called FilterIndex, and it works on the principle that search engines use: instead of going through all the products and their attributes every time a user requests, we build an optimized table in advance that already has all the necessary links “product - attribute - value - price - availability”.
How does this work technically? When an administrator configures filters—for example, adding filtering by brand, viscosity, and oil type—the system launches a background task through the Action Scheduler. This task goes through all the products in the catalog and for each product records a set of rows in a separate wpaic_filter_index table: product such and such, the “Brand” attribute, the “Shell” value; product such and such, attribute “Viscosity”, value “5W-30”; and so on. Plus, the product price, availability status, category and other information that may be needed for filtering are added to each line. Essentially, we take data scattered across dozens of WordPress tables - wp_posts, wp_postmeta, wp_terms, wp_term_relationships, wp_wc_product_meta_lookup - and put it into one flat table with the correct indexes.
Result? A query that, in standard WooCommerce filtering, required four to five JOIN operations on the gigabyte-sized wp_postmeta table and was completed in one and a half to two seconds, is now completed in thirty to fifty milliseconds. This is not a theoretical figure - these are real measurements on a catalog of sixteen thousand products with ninety-nine attributes. The difference in speed is thirty to forty times. And the buyer literally feels this difference: he clicks on the filter - and the goods appear instantly, without any waiting.
But a precomputed index has an obvious question: what if the data has changed? Added a new product, changed the price, updated balances from 1C? This is where the hook system comes into play. When you change any product - through standard editing in WordPress, through the REST API, through import from 1C - a hook is triggered that updates the corresponding rows in the index. Moreover, it does not update the entire index, but only the rows of a specific product. A complete rebuild of the index is launched only at the administrator's command or on a schedule - for example, once a day to guarantee consistency. In normal mode, the index is kept up to date incrementally, almost in real time.
I remember one client, the owner of a store with twenty thousand products, asking me: “Are you sure that the index will not get out of sync?” This is a fair question - I asked myself this myself at the design stage. And the answer is: yes, under certain circumstances - for example, when directly editing the database past WordPress - the index can lag. That is why in the control panel there is a button for manually rebuilding the index and setting up automatic rebuilding via cron. But in normal mode, when products are changed via WooCommerce or through our 1C connector, desynchronization is excluded.
Another point that I think is important: the index stores not only the attribute values, but also the number of products for each value. This is what is called “faceted counters” - when next to each filter value the number of products that match it is shown. In standard WooCommerce filtering, these counters are either not shown or require an additional query to the database. In our case, the counters are calculated right at the time of the request, with virtually no additional costs, because the index already contains all the necessary information. And when the buyer selects “Shell” in the filter by brand, he immediately sees that there are twelve Shell motor oils with a viscosity of 5W-30, and eight with a viscosity of 10W-40. This eliminates the “selected parameter - got zero results” situation, which wildly irritates buyers.
Speaking of zero results. One of the problems with standard filtering is the so-called “dead combinations”. The buyer selects the brand, then the type of oil, then the viscosity - and receives a blank page, because there are no products with this combination of parameters. In our filter, dead combinations are blocked automatically: after each parameter selection, the counters for all other values are recalculated, and values with zero products are either hidden or shown inactive. The buyer physically cannot come to an empty selection - the system guides him, showing only relevant options.
Visual filters and swatches: when the interface sells
Honestly, filtration speed is fundamental, but not what the buyer notices first. The first thing that catches your eye is the appearance of the filters. And here with standard WooCommerce everything is completely sad: drop-down lists with text values. “Red”, “Blue”, “Green” - written in text. Now imagine that you are selling paint, fabric, furniture or clothing. The buyer needs to see the color, not read its name. He wants to click on the red circle and see all the red products. Or click on the Bosch logo and see everything from Bosch, without remembering how to spell the name - Bosch, BOSCH or Bosch.
We have implemented three types of visual filters. The first is color swatches. Each value of the “Color” attribute can be assigned a HEX color code, and in the filter, instead of a text list, the buyer sees a series of colored circles. Clicked on red and received red goods. Moreover, the circles are not just static - the selected color is highlighted by a frame, and when hovered over, a tooltip with the name is shown. The second type is buttons. This works well for sizes (S, M, L, XL, XXL) or discrete sizes (500ml, 1L, 5L, 20L). Instead of a drop-down list, there is a series of neat buttons that can be clicked and combined. The third type is logos. For the Brand attribute, each value can be loaded with a logo image, and the buyer chooses the brand by visual image rather than text. This is especially important for stores with international brands, where the customer may have a better visual memory for the logo than for the spelling of the name.
And here I want to specifically focus on the swatches not in the filter, but on the product card. Because it is a related but separate task. When the buyer finds a product through the filter and goes to the card, he needs to select a specific option. Color, size, volume - in WooCommerce this is implemented through variable products and standard drop-down lists. And these lists are one of WooCommerce's biggest missed opportunities in terms of conversion.
Our swatch module replaces drop-down lists with visual elements directly on the product card. For color - circles with real color. For size - buttons. For the brand - logo miniatures. But the most important thing is that when you select an option, the product image automatically changes. The buyer clicks on the blue circle - and the blue version appears on the main photo of the product. Clicks on red - sees red. This is a small thing from a technical point of view, but from a marketing point of view it is a huge lever. A buyer who sees a product in the color they want is much closer to purchasing than someone who only sees the text “Blue” and has to imagine what it looks like.
I conducted informal research on three projects where we implemented swatches. Before implementation, the conversion from product card to cart averaged eight percent. After the introduction of visual swatches with automatic image changes - eleven to twelve percent. An increase of thirty to fifty percent. It is clear that this is not a pure A/B test, and there were other factors, but the trend is clear. People buy what they see, not what they read.
Another nuance that seems important to me: swatches and visual filters should be a single system. If in the catalog filter “red” is a circle with the color #FF0000, and on the product card “red” is the text in the drop-down list, the buyer feels disconnected. In our plugin, the swatch settings are global: you once assign the “Color swatch” display type to the “Color” attribute and set HEX codes for each value - and then these swatches are used everywhere: in the filter, on the product card, in widgets, in search results. One setting - a single visual language throughout the store.
But let's talk about what happens below the product list - pagination. Because even an ideal filter will not help if after filtering there are two hundred products left and the buyer needs to switch pages to see them all.
“Show more” instead of pagination: small button, big effect
Do you know what always surprised me about WooCommerce? Standard pagination - “1, 2, 3, ... 15, Next” - was invented in an era when each page was fully loaded and the user was sitting at a desktop with a mouse. Today, more than sixty percent of customers come from mobile devices, and for them, switching pages is a pain. Small links that you need to hit with your finger, plus each transition means a page reload, plus loss of scroll position. Ozon and Wildberries long ago replaced this with a “Show more” button and endless loading, and it’s no coincidence - it’s just more convenient.
In our plugin, we have implemented the Load More module, which replaces the standard WooCommerce pagination with a “Show more” button. The buyer scrolled to the end of the current portion of goods, pressed one large button - and the next portion is smoothly added to those already loaded. No reloading, no loss of scroll, no need to aim for small pagination numbers. And this works great in conjunction with the AJAX filter: the buyer selected the parameters, saw the first twenty products, clicked “Show more” and saw twenty more. Everything on one page, everything without flickering.
Technically, it works like this: when a button is clicked, JavaScript sends an AJAX request with the current filtering options and the next “page” number. The server returns the HTML markup for the next batch of products, and the script inserts it into the DOM after the last product. The URL in the address bar does not change, the scrolling is preserved, and the selected filters remain in place. To the buyer, it appears as if items simply “appear” at the bottom of the list.
But there is a subtlety that I want to talk about, because many developers stumble on it. When you use infinite loading on WooCommerce, you need to properly handle the situation when you run out of products. If the buyer has reached the last portion, the “Show more” button should disappear, and it is advisable to show an unobtrusive message “All products are loaded.” It sounds trivial, but I've seen implementations where the button continued to display and returned an empty response when clicked, leaving the customer confused. Or, conversely, the button disappeared, but when changing filters it did not appear back, and the buyer saw only the first twenty products out of two hundred. In our module, the button is state-controlled: it knows how many products are left and shows this to the buyer - “Show more (45 left).” When filters are changed, the counter is reset and recalculated automatically.
There is one more thing that I think is critical for mobile users: button size and placement. Standard WooCommerce pagination links are small numbers that are difficult to reach with your finger on a phone. Our Show More button is a full-width button with large text that you can't miss. It is stylized to match the overall design of the store through CSS variables, and the administrator can customize its color, rounding, and indentations - but by default it already looks good and, most importantly, is easy to click on from any device.
And this brings up a question that I get asked regularly: what about SEO? If all products are loaded via AJAX, how will search bots see the full catalog? This is a truly important question, and the answer lies in architecture. Our Load More module does not replace server-side pagination, but complements it. The HTML code of the page contains standard links to the following pages - rel="next" and rel="prev". A search bot that does not execute JavaScript follows these links and indexes all directory pages as normal. And the buyer, whose JavaScript is running, sees a “Show more” button instead of pagination links and loads products via AJAX. Thus, we get the best of both worlds: a convenient UX for the buyer and full indexing for the search bot.
By the way, about the combination of filter and loading. When the buyer changes the filter parameters, the Load More module is automatically reset: the first portion of products according to the new criteria is shown, the counter is reset, and the button updates the number of remaining products. This seems obvious, but in practice, integrating the two AJAX modules—filtering and loading—requires careful coordination. They have to use a common state, and we spent a lot of time making this connection seamless.
Now let's talk about how this all works on mobile devices. Because mobile filtering is a different story, with its own problems and solutions.
On desktop, filters are usually located in the sidebar to the left of the product list. The screen is large, there is enough space, the filter panel is always visible - click and select. There is no such luxury on mobile. The sidebar simply does not fit next to the products on a screen three hundred and ninety pixels wide. And here there are two typical solutions, both unsuccessful. The first is to show filters above products, a long list. The buyer sees a screen full of filters and must scroll through them to see at least one product. The second is to hide the filters in a standard accordion element or drop-down block. The buyer clicks - the filters open, but at the same time they move the products down, and everything jumps on the screen.
We took the third route: a collapsible filter panel in the form of an overlay. On a mobile device, the buyer sees a “Filters” button - usually at the top of the catalog, next to the sorting and quantity of products. When you click this button, the filter panel slides out from the side - like a menu on many mobile sites - and takes up about eighty percent of the screen. The buyer selects the necessary parameters, clicks “Show” - the panel closes and the products are updated. It is important that in this case the products are updated in real time, right while the panel is open: the buyer sees the “Found: 42 products” counter on the “Show” button, and this counter is updated every time the filter is changed. This gives the buyer immediate feedback on whether he is narrowing down his selection too much or not.
Another trick we use on mobile is “chips” of selected filters. After closing the filter panel, compact “chips” appear above the list of products - small bars with the selected values: “Shell”, “5W-30”, “In stock”. Each chip can be removed with one tap by removing the corresponding filter. This is much more convenient than opening the panel again to remove one parameter. And this saves the buyer time - and time on mobile is doubly valuable, because mobile sessions are usually shorter than desktop ones.
An interesting thing I noticed is that on mobile devices, consumers on average use fewer filters at once - usually one or two, three at most. But they use them more often and faster. Therefore, response speed is critical: fifty milliseconds of index response plays an even greater role here than on the desktop. If a mobile customer clicks on a filter and waits more than a second, he will most likely decide that something is broken and start clicking again. And double-clicking on a filter usually means selecting and immediately canceling - and the buyer is left with where he started, only annoyed.
Let's now talk about a situation that many store owners face: migrating from an existing solution. Because most WooCommerce stores are not built from scratch - they already have some kind of filter, usually YITH Ajax Product Filter or WooCommerce Product Filter from another developer.
Migration from YITH and other filters: how not to lose data and nerves
I have repeatedly encountered a situation where a store has been using YITH Ajax Product Filter for years, and the owner wants to switch to something else. There are different reasons: YITH stopped updating, began to conflict with the theme, works too slowly on a large catalog, or simply got tired of paying separately for a filter, separately for swatches, separately for pagination. And the first question the owner asks: “Will the filter settings be saved?”
Let's be honest: there is no 100% automatic migration of settings between different filtering plugins. Too different architectures, too different ways of storing configuration. YITH stores its presets in WordPress options and postmeta, other plugins use custom tables, and others use JSON files. But you don’t need to migrate manually either - our module has a migration tool that analyzes installed filtering plugins and offers mapping of settings.
How does this work in practice? When you first activate our filtering module, the system checks to see if YITH Ajax Product Filter (or YITH WooCommerce Ajax Product Filter Premium) is installed. If yes, the “Migration” tab appears in the settings interface with information about the found YITH presets, configured filters and their types. The administrator sees what attributes were configured in YITH, what display types were used (checkbox, drop-down list, color swatch, price slider), and can start the migration with one button. The system creates similar filters in our module, maps display types (YITH “color” → our “swatch”, YITH “label” → our “button” and so on) and builds an index.
But I want to warn you: after migration, you definitely need to check the result manually. Not because migration is unreliable, but because it is an excellent reason to reconsider the filter structure. It often happens that filters in YITH were configured two or three years ago, since then the range has changed, new attributes have appeared, some values are outdated - and the migration blindly copies everything as is, including settings that are no longer relevant. I encourage clients to use migration as a starting point, then go through each filter and ask themselves, “Does the customer really need this?”
By the way, one of the most common questions during migration is “what will happen to the URL?” YITH has its own format for filtering URLs (usually with hashes or custom parameters), while our module has its own. If you actively used filtering URLs in advertising or internal links, these URLs will no longer work during migration. In such cases, I recommend setting up redirects through our SEO redirects module, which supports regex patterns. A couple of rules - and old filtering links will be correctly redirected to new ones.
Another practical tip from migration experience: do not disable the old filter before you have fully configured the new one. It sounds obvious, but I've seen people deactivate YITH, activate our module and start configuring - while the live store runs without filtering at all. This may take an hour or two, and during this time you will lose some sales. It is better to set up a new filter in parallel (it will not conflict until its shortcode is placed on the page), make sure that everything works, and switch at the same time.
I want to once again emphasize the idea that I return to constantly: catalog filtering is not a technical feature, but a sales element. Every store that has migrated from WooCommerce's standard filtering or legacy plugin to our AJAX pre-index filter has seen an improvement in behavioral metrics. Reduced bounce rate on the catalog page, increased browsing depth, increased time on the site. And, most importantly, an increase in conversion from viewing the catalog to adding to cart. Because when a customer quickly finds what they need, they are more likely to buy it.
Let's now talk about how all this comes together into a single system and why the “one plugin for everything” approach is of fundamental importance here.
Do you know what I think is the main problem with the “filter from one developer, swatches from another, pagination from a third” approach? These are not plugin conflicts, although they also happen. This is the user experience gap. The buyer selects a color in the filter and sees a beautiful circle. Goes to the product card - and there is a text drop-down list. Clicks “Show more” - and the filters are reset, because the pagination plugin does not know about the filtering plugin. Each of these plugins works great on their own, but together they create the feeling of Frankenstein - stitched together from different pieces, uneven, with protruding seams.
When filter, swatches, product loading and indexing are part of the same module, they share a common state. The filtering JavaScript code knows about the loading module and interacts with it correctly. Swatch settings are applied the same way in the filter and on the product card. The filtering index takes into account data that is updated through other plugin modules - 1C synchronization, bulk editing, import. This is not just convenience for the developer - it is a fundamentally different level of user experience for the buyer.
I often use the analogy of a car. You can assemble a car from parts from different manufacturers: an engine from one, suspension from another, electronics from a third. Technically this is possible, and every detail can be of excellent quality. But a car designed as a whole will drive better - because engineers have optimized the interaction of all components, rather than each component individually. It’s the same with an online store: the buyer does not need the best filter in the world, the best swatches, and the best pagination. He needs a catalog that works as a whole - quickly, beautifully and predictably.
And here I want to return to the topic with which I started - speed. Because the precomputed index is not the only optimization we made. There are several other things that affect the perceived filtration rate. First, an optimistic update: when a shopper clicks on a filter, the product grid instantly receives a CSS “loading” effect—a slight dimming or blurring—and an AJAX request is sent at the same time. When the response arrives (after thirty to fifty milliseconds - I remind you), the products are updated and the loading effect is removed. For the buyer, this looks like an instant reaction: he clicked - the grid “blinked” - new goods are in place. Moreover, it “blinked” so quickly that the buyer perceives it not as an expectation, but as a visual confirmation of the action.
Secondly, client-side caching. If the buyer selected “Shell, 5W-30” and received twelve products, then removed “5W-30” and looked at all Shell oils, and then put “5W-30” again - the second time the same request will not go to the server, but will be sent from the browser cache. This saves traffic and speeds up navigation during “return” filtering when the buyer tries different combinations back and forth.
Thirdly - and this is perhaps the most unobvious optimization - we send from the server not the full HTML of product cards, but the minimum required. A standard WooCommerce product card template in a catalog can contain dozens of hooks, each of which adds HTML: a comparison button from one plugin, a favorites icon from another, a rating from a third. On a page with twenty products, this could be two or three hundred kilobytes of HTML. We optimized the server rendering so that the AJAX response contained only the required minimum, and additional elements (compare buttons, swatches, icons) were initialized on the client after inserting cards into the DOM. The result is that the server’s response is three to four times easier, and with a slow mobile Internet this is a noticeable difference.
Finally, the last thing I want to talk about is filtering analytics. We have built statistics collection into the filtering module: which filters are used most often, which combinations are selected, which values are never clicked, how many times buyers come to a zero result. This data is available in the control panel and helps the store owner optimize the catalog. If you see that the “Country of Manufacture” filter is used in zero point two percent of filtering, it may be worth removing it so as not to clutter the panel. If you see that customers often filter by brand and immediately by viscosity, it makes sense to put these two filters first. If you see that on mobile customers only use the price slider and brand, you can hide the remaining filters for the mobile version, showing them only with a separate “All filters” tap.
Here's the thing: directory filtering is not "set it and forget it." This is a living tool that needs to be customized to suit your product range and your customers. And the more data you collect about how buyers filter, the more precise you can customize. We try to give the store owner not just a filter, but a tool for understanding how customers search for products.
When I started designing this module, I set myself a simple goal: so that a buyer in an online store on WooCommerce could find a product as quickly and conveniently as on Ozon or Wildberries. Not “almost the same” and not “with some restrictions”, but really the same. Instant filtering without reloading, visual swatches instead of text lists, endless loading instead of numbered pages, convenient mobile filter panel. And so that all this works quickly - not in seconds, but in tens of milliseconds.
Did it work? I think so - but not because we wrote brilliant code, but because we set our priorities correctly. We started not with a beautiful interface, but with performance - with a pre-computed index. Because a beautiful filter that slows down is still a bad filter. And then they built a convenient interface on top of the fast core: swatches, chips, a mobile overlay, a download button. And they connected it into a single system, where each element knows about all the others.
If you're currently looking at your WooCommerce store and seeing standard drop-down lists in filters, numbered pagination at the bottom of the catalog, and page reloads with every click - think about how many customers you're losing every day. Not because of the prices, not because of the assortment, but because it is simply inconvenient for them to search. The AJAX filtering module in COS WP Woo solves this problem comprehensively: filtering, visual display, loading, mobile adaptation, indexing and analytics - all in one plugin, without the need to buy and configure five different solutions. Try it and look at your metrics in a week. I'm sure the numbers will surprise you.
And now - an honest conversation about pitfalls. Because I don’t like articles in which everything is perfect and not a single minus. Any technology has its limitations, and AJAX filtering is no exception.
The first pitfall is server-level caching. If you have LiteSpeed, Varnish, nginx FastCGI cache or any other server cache, AJAX filtering requests should bypass it. It sounds simple, but in practice it requires proper configuration. AJAX requests go to the same wp-admin/admin-ajax.php or to a custom REST endpoint, and the server cache can start caching filtering results. As a result, the buyer selects “Shell” - but sees the results for Lukoil, because the cache returns the answer from the previous request of another buyer. We solve this in two ways: first, we use POST requests for filtering (server caches usually do not cache POST), and second, we add no-cache headers to the responses. But if you set up server caching yourself, keep this in mind, because a cached AJAX filter is not just a bug, it’s a bug that shows someone else’s results to the buyer.
The second stone is accessibility. When all content is updated via JavaScript without reloading the page, screen readers and other assistive technologies may not notice the change. We add ARIA attributes to the product area (aria-live="polite") and announce changes for assistive technologies with every update. This is not noticeable to the average consumer, but is critical for people using screen readers. And, by the way, this affects the accessibility score in Lighthouse, which is increasingly becoming a ranking factor.
The third point is heavy catalogs with custom fields. If your products do not use standard WooCommerce attributes, but custom fields (ACF, our CF module or just wp_postmeta), indexing these fields requires additional configuration. Standard WooCommerce attributes (pa_color, pa_size, and so on) are indexed automatically, but custom meta fields must be explicitly specified in the filter settings - which field to index and how to display it. We made the interface for this as simple as possible: select the meta key from the drop-down list, specify the display type (checkbox, slider, swatch) - and the system includes this field in the index during the next rebuild. But you need to know about this in advance so as not to be surprised why the new “Pour Point” filter does not show a value - because you forgot to include it in the index.
And the last thing is performance with a very large number of simultaneous filters. Our index works great with five to ten simultaneously active filters, but if you have a catalog with thirty attributes and the buyer has turned on twenty filters at the same time, the response time can increase to one hundred to one hundred and fifty milliseconds. This is still very fast compared to standard WooCommerce (where such a request would take five to ten seconds), but noticeably slower than fifty milliseconds for simple filtering. In practice, such situations rarely arise - buyers usually use three to five filters at a time - but if you have a specific catalog with a lot of technical characteristics, it is worth taking this into account when designing the interface. You can, for example, divide filters into “main” (visible immediately) and “additional” (opened by clicking) to reduce the likelihood of using twenty parameters at the same time.