How We Made Our Plugin 30x Faster ![rw-book-cover](https://pbs.twimg.com/profile_images/1803441953704402944/TvrkVD5-.jpg) ๐Ÿ”— **Source:** [How We Made Our Plugin 30x Faster](https://twitter.com/rossmorsali/status/2092655210338361521/?rw_tt_thread=True) > [!note]+ Document Notes > --- > tags: [wordpress-performance, faceted-search, bitmap-indexes, ai-assisted-development, benchmarking] > author: Ross Morsali > source: X (@rossmorsali) > reference: https://twitter.com/rossmorsali/status/2092655210338361521 > date created: 2026-09-12 > --- > > [!info] Generated analysis โ€” not the author's words. Sections below are machine-written > > from the captured source. Only text inside `> [!quote]` blocks is verbatim from the author. > > Do not quote or attribute any other line to the named author. > # ๐Ÿท๏ธ Title: How we made our plugin 30x faster > ## ๐Ÿงญ Table of Contents > - [๐Ÿ“ Summary](#-summary) > - [๐Ÿ“– Main Content](#-main-content) > - [๐Ÿ—’๏ธ Notes](#๏ธ-notes) > - [๐Ÿ“š References](#-references) > - [๐Ÿ—ฃ๏ธ Paraphrase](#๏ธ-paraphrase) > - [๐Ÿ“ฐ Newsletter](#-newsletter) > - [โœ… Action Items](#-action-items) > - [๐Ÿงช Hypotheses](#-hypotheses) > - [๐Ÿ“Š Methodology](#-methodology) > - [โ“ Questions](#-questions) > - [๐Ÿ”ฎ Future Research](#-future-research) > - [๐Ÿ’ก Implications](#-implications) > - [๐Ÿง  Learning Styles Assessment](#-learning-styles-assessment) > - [๐Ÿ“Š Accessibility Assessment](#-accessibility-assessment) > - [๐ŸŒ DEIB Assessment](#-deib-assessment) > - [โœ… Logical Validity](#-logical-validity) > - [๐Ÿ›ก๏ธ DARVO Analysis](#-darvo-analysis) > - [๐ŸŽฏ Conclusion](#-conclusion) > ### ๐Ÿ”— References (in-page) > - The article links only to the @SearchAndFilter account (checked against the stored HTML). It links no benchmark suite, code, dataset, research sources, or release notes. > - One embedded image: a line chart titled by alt text "How we made our plugin 30x faster," plotting "Total workload" for "Historical" vs "Current" at 2kโ€“40k posts/products. > ## ๐Ÿ“ Summary > - **What happened.** On 2026-08-26 Ross Morsali published an X article on rewriting the indexer of Search & Filter, a WordPress faceted search plugin by Code Amp. The rewrite took about three months. The author credits AI "deep research" for finding techniques and agent goal loops for micro-optimizations, then picked approaches by benchmarking. > - **The technique.** Filtering combines large sets of post IDs. The new indexer represents those sets as bitmaps (inspired by Roaring Bitmaps, which the author says most WordPress hosts can't run), splits indexing into three table designs by filter type (range buckets, choice-field inverted indexes, a parent map for WooCommerce variations), and adds a native search index with BM25 scoring, typo tolerance, and a separate autocomplete index. > - **The numbers.** Uncached frontend queries: 102 ms โ†’ 23.2 ms at 2,000 posts (4.4x) and 1.44 s โ†’ 50.7 ms at 40,000 posts (28.4x). Both ratios check out. The title's "30x" rounds up 28.4x. > - **Why it matters.** Faceted filtering on large WooCommerce and content sites is a common WordPress performance bottleneck. The post shows a way to find data structures outside the usual "post ID mapped to field value" index while staying inside PHP and MySQL. > - **Risks and tradeoffs.** The benchmark method isn't published: no hardware, PHP or MySQL versions, filter configuration, run counts, or which "previous version." The chart's values don't match the text's. The benchmarks were written "using AI," with no mention of review. The company's January 2026 release post claimed "10x," and the article doesn't reconcile the two figures. > - **Bottom line.** A useful account of a technique change (bitmaps plus type-specific tables) and a method (research breadth-first, then benchmark everything), with performance claims that can't be reproduced from what's published. > ## ๐Ÿ“– Main Content > - **The core problem.** A faceted search plugin repeatedly intersects and unions large arrays of post IDs, once for results and again for each facet's option counts. Combining arrays in PHP is the cost the rewrite attacks. > - **Step 1, micro-optimizations.** An agent running a `/goal` loop found many small wins that "did add up, but nothing out of this world." The post doesn't name the agent tool. > - **Step 2, research breadth-first.** The author asked AI deep research what large-scale systems use for this, telling it not to rule anything out, then looked for what could run inside WordPress. > - **Bitmaps.** A bitmap stores set membership as one bit per ID, so combining two filters becomes a bitwise operation over compact data instead of an array operation over thousands of integers. Roaring Bitmaps add compression; roaringbitmap.org lists them in Apache Lucene, Elasticsearch, Druid, Spark, and ClickHouse. > - **PHP constraint.** The author says Roaring Bitmaps "are not available on most WordPress hosts," so the plugin uses bitmaps in PHP with "alternative compression techniques," which the post doesn't name. > - **Type-specific tables.** Range fields use bitmap buckets; choice fields use a bitmap inverted index; WooCommerce variations use a parent map (nested document pattern). > - **Facet counts.** The author says facet counts are the most demanding part, and that combining per-filter bitmaps beats array approaches there. > - **Search.** A new native search index adds BM25 scoring, fuzzy and typo-tolerant matching, and a separate autocomplete index. > - **Step 3, benchmark everything.** For each plausible option the team built benchmarks (written with AI) across PHP versions and server configurations, then chose the fastest options that work in restricted environments. > - **Caching caveat.** All figures are uncached. With Redis or the plugin's database caching, repeat hits on the same filter combination get faster after the first request. > - **Closing advice.** Combine deep research (for options outside the model's default knowledge) with self-improving agent loops (for iteration). > **Terms** > - *Faceted search:* filtering with multiple independent criteria, each showing how many results each option would return. > - *Bitmap (bitset):* a sequence of bits where position N marks whether item N is in the set. > - *Roaring Bitmap:* a compressed bitmap format that switches container types by data density. > - *Inverted index:* a map from each field value to the set of items that have it. > - *BM25:* a standard relevance-ranking function for text search. > **Uncertainties and contested claims** > - **Benchmark conditions** are unstated, so the 4.4x and 28.4x figures can't be reproduced or compared. > - **Chart vs text.** Read by eye from the image, the chart's "Historical" line is about 250 ms at 2k and about 4.45 s at 40k, while the text says 102 ms and 1.44 s. The chart's "Total workload" likely aggregates more than one query, but the post doesn't say. > - **10x vs 28.4x.** The Search & Filter 3.2.0 release post (2026-01-09) described the rewritten indexer as "10x faster (and more in some circumstances)" and promised "our upcoming performance articleโ€ฆ (with benchmarks!)." The X article matches that promise but doesn't say whether the gap reflects later work or a different measurement. > - **Distribution.** The free Search & Filter listing on WordPress.org is still version 1.2.18 (Code Amp, 50,000+ active installs, updated 2026-08-22), with a changelog notice that "Version 3 is coming soon." The rewritten v3 indexer ships from searchandfilter.com, not that listing. > ## ๐Ÿ—’๏ธ Notes > - Published 2026-08-26 as an X article; 896 words. > - Rewrite of the Search & Filter indexer "from the ground up"; about 3 months. > - Faceted search backbone: huge post ID arrays combined repeatedly per filter. > - Micro-optimizations via an agent `/goal` loop: cumulative gains, none large. > - WordPress plugins are limited to PHP plus MySQL or MariaDB. > - Most WordPress filter plugins map post IDs to field values in an index. > - Research question: what do large-scale systems (the post's example: "the Amazons of the world") use, and can any of it run in WordPress? > - Win 1: bitmaps (Roaring-inspired); implemented in PHP with alternative compression. > - Example: a filter matching 20,000 posts means 20,000 IDs in a traditional index, versus one compact binary structure. > - Win 2: three subsystems by filter type: range buckets, choice-field inverted index, WooCommerce variation parent map. > - Facet option counts are the heaviest workload; bitmap combination is faster than PHP arrays there. > - Win 3: native advanced search with fuzzy matching, BM25, autocomplete, and a separate autoco ![How we made our plugin 30x faster](https://pbs.twimg.com/media/HQqaAdwXIAAJzds.jpg) We rewrote [@SearchAndFilter](https://x.com/@SearchAndFilter) 's indexer from the ground up. It took us 3 months to complete and heavily leveraged AI's deep research mode combined with iterative goal loops. The backbone of faceted search is (post) IDs... Huge arrays of them, and you need to combine them repeatedly in different ways depending on the filters you've built. That's the main problem really - how can you do this as fast as possible? #### 1 - Micro-optimisations (the step I think most are doing already) The easier thing you can do today is set up your agent to run a `/goal` loop looking for performance improvements. We managed to do lots of micro optimisations which did add up, but nothing out of this world. #### 2 - Deep research to look at what else is out there WordPress plugins are always going to be restricted by the environment - PHP + a relational database (MySQL/MariaDB). Most filtering plugins in WordPress use roughly the same approach across the board, ultimately creating an index where post IDs are mapped to the field values somewhere. So the research angle was: what are the Amazons of the world doing for this at scale and is there anything we can use that we can run inside WordPress? I asked AI to find all the different techniques that are being used out there, breadth first (I always tell it not to rule anything out). **Win 1 - Switching to Bitmaps** The first big win was finding that large-scale systems often use Roaring Bitmaps, which use some clever compression and bitmap-based structures to represent large sets of post IDs much more efficiently than storing each ID individually. In a bitmap, *any* post ID is effectively represented as either a single `1` or a `0` depending on whether it's included. With a traditional index, a filter matching 20,000 posts might mean dealing with 20,000 individual IDs. With a bitmap-based approach the whole set can be represented and combined as a compact binary structure. That can dramatically reduce how much data needs to be stored, loaded into memory and moved around when combining large result sets. Unfortunately Roaring Bitmaps are not available on most WordPress hosts. But we can still use bitmaps in PHP with some alternative compression techniques, which allowed us to achieve something similar in spirit. **Win #2 - Table Structures based around different filter types** We also found that different types of data and queries benefit from different data and table structures. We ended up splitting our indexer into three subsystems, orientated around the new bitmap first approach and tailored to the type of task they would be doing (i.e. the filter type): * A bitmap-based bucket system for range fields (like price or date ranges) * A bitmap-based (inverted index) system for choice fields (colour, size etc) * A parent map/nested document pattern for efficiently handling WooCommerce product variations. All of these new systems contribute to much faster queries, but the most demanding part of this is the faceted part and figuring out which options can be shown and how many results in each option. That's where bitmaps win again, because our indexer and tables are designed around bitmaps, combining bitmaps for each filter to get the final result set IDs is much faster than any array based approach in PHP. **Win #3 - Adding the things that were always missing** While we were deep into this huge refactor I decided to finally address the elephant in the room - something that's been on our to-do list since pretty much day 1: **Native Advanced Search** - i.e., fuzzy/typo tolerant search, with BM25 scoring and autocomplete - I like to say we put the "Search" back into "Search & Filter" (cheesy, but true). We added a proper search indexing system built for scale and a separate index just for autocomplete suggestions to keep that snappy. #### 3 - Choosing which research results to go with (answer: benchmark everything) There were a lot of ideas and techniques that surfaced from the deep research tasks. For each plausible option we built a suite of benchmarks (using AI of course), pitting the ideas against each other across different PHP versions and server configurations, and then we went with the fastest options that could work in restricted environments. Self-improving agent loops are good, but they usually use their own baked in knowledge and I really like deep research mode because it gets you more options and things to try. So that was around 3 months of research and building, end to end. So that was around 3 months of research and building, end to end. Oh and little about the data... For frontend query speeds (**uncached**): On a site with 2,000 posts, the query could have take 102 ms, vs 23.2 ms - **4.4x faster**. As a site gets larger, the gains get even wilder. A site with 40,000 posts, the previous version could have taken 1.44 seconds vs new: 50.7 ms... That's **28.4x faster** - we went from unmanagable to something you can realistically run. These results are all raw query performance, if you used caching on your site (like Redis or our built in database caching layer), these will come down a lot after the first hit on a specific filter combination. --- So if you're optimising a plugin with AI, I strongly recommend using both deep research mode for more outside the box thinking combined with self improving agent loops., How We Made Our Plugin 30x Faster, Ross Morsali, 01m2b0rrbws56b9epvf9ahqvdb.