ECommerce Custom Search

Tumisu search

A WooCommerce retailer came to me running a catalog of around 900 products, a lot of them digital downloads. Search and category browsing ran on Algolia InstantSearch, wired up by a previous agency through two custom plugins. The bill was $200 a month, $2,400 a year, and the search itself worked fine. The problem was everything around it.

The previous setup

Algolia’s InstantSearch renders the entire product grid in the browser. Someone hits a category page, Algolia’s cloud returns matching products as JSON, and a JavaScript library paints the product cards client-side. Quick to query, slick on the surface. But the moment rendering moves to the browser, none of WooCommerce’s PHP hooks fire. None of them.

That matters more than it sounds. Every plugin that hangs off WooCommerce (the wishlist, the audio player, variation forms, add-to-cart) expects the product card to render server-side so it can hook in. With Algolia doing the rendering, every one of those integrations had to get rebuilt by hand in JavaScript inside the search plugin.

I’m not going to pretend FULLTEXT is Algolia. A hosted engine like that gives you fuzzy matching, typo tolerance and synonyms close to free, and if this were a 50,000-product catalog I’d have reached for Elasticsearch instead. With 900 products none of that was worth $2,400 a year and a broken plugin ecosystem for the client. The right tool is the one that fits the actual problem, not the one with the best marketing page.

Why it had to go

Re-implementing WooCommerce in JavaScript is exactly as brittle as it sounds. The wishlist sent the wrong product IDs on page load because the variation form hadn’t resolved yet, so the heart icons showed the wrong state until you toggled a dropdown. Nonce URLs came out double-encoded and broke. A class-stripping hack for the wishlist shifted the add-to-cart button width every time a card painted. Paper cuts that add up.

I’d been holding it together with a mu-plugin whose only job was patching the gaps between Algolia and the wishlist. And every time the store wanted to add another WooCommerce plugin, the answer was the same: someone goes and writes custom JavaScript to make it render inside Algolia. That’s not a search setup, that’s a maintenance tax.

The bet

So I made a bet. Bring search back to the server, render it through WooCommerce’s own product loop, and let every plugin work the way it was built to. The only thing in the way was speed. Algolia exists because hosted search is fast, so I had to prove I could match it without paying for it.

How it works

The replacement is a custom REST endpoint. A query comes in, it checks Redis first, and on a cache miss it hits a MySQL FULLTEXT index to pull the matching product IDs. Then, and this is the whole point, it renders those products through WooCommerce’s standard loop. Every hook fires. The wishlist, the audio player, variations and add-to-cart don’t know anything changed. The rendered HTML goes into Redis, and the frontend swaps it into the page.

No external service. No client-side rendering. No custom JavaScript override for each plugin. MySQL and Redis were already running on the box, so the query layer cost nothing to stand up.

The (real) numbers

This was the part I had to be sure about before recommending it, so I benchmarked it on the real catalog.

EventTime
Keyword search (MySQL FULLTEXT)2.5ms
Redis cache round trip0.3ms
All filter facet counts, one pass~110ms
Algolia’s hosted API (for comparison)107-130ms
Cached page via Nginx, zero PHP~5ms

A keyword search against the FULLTEXT index came back in 2.5ms. A Redis round trip was 0.3ms. Counting every filter facet in a single pass ran about 110ms. Algolia’s own API was landing at 107 to 130ms, so the homegrown query layer matched the hosted service and beat it on the simple stuff.

The latency that actually mattered was never the query. It was WordPress booting 40-plus plugins on every uncached request, which is true of any PHP page on the site and has nothing to do with search. Nginx page caching wipes that out: a cached page serves in about 5ms with no PHP running at all. (Getting that cache to engage meant chasing down a WooCommerce session cookie that was bypassing it for every anonymous visitor, but that’s its own story.)

Two additional things I fixed while I was in there

The old “related products” was keyword-matching on the product title, which is about as useful as it sounds. I replaced it with real related-product logic and built a frequently-bought-together feature that runs against 20-plus years of order history. About half the store’s orders have more than one item, so there was plenty of signal to work with.

What changed

Every plugin works natively again. I deleted the previously wishlist plugin custom patch because there was nothing left to fix. Adding a new WooCommerce plugin is back to being a normal afternoon instead of a JavaScript project. The store owns the whole search stack now: no vendor, no monthly bill, no external dependency that takes the storefront down with it if pricing changes or the service has a bad day. And, it’s $2,400 a year back in the budget.


If your agency’s dealing with something like this (or you’d rather have someone on call before it turns into an emergency), I keep a few retainer spots open for exactly this kind of work. Book a call and we’ll figure out if we’re a fit.

What To Expect

30 minutes.

No pitch deck.

I’ll ask about your team, your projects, and where you’re getting stuck.

  • We’ll talk about your current dev workflow
  • I’ll tell you if I can help (and if I can’t, I’ll try to point you in the right direction).
  • No contracts or commitments from this call

Pick a date and time

Have a one-off project instead? Tell me about it here.