Booknetic SaaS ships a built-in tenant directory: a page where the people running a booking platform can list all the businesses on it, so visitors can find a salon, a clinic, a studio and book. It works. But “it works” and “it sells your platform” are different things, and the gap between them is exactly where I built Tendir Pro.
The problem
The stock directory is honest and bare. A flat list of tenants, a search box, not much else. If you’re the owner of a booking platform, this is one of the first things a prospective customer sees when they’re deciding whether to host their business with you. It’s your storefront. And the default storefront looks like a database printout, not a place anyone wants to browse.
I kept running into the same reaction from platform owners: they were quietly embarrassed by it. They’d built a real business on top of Booknetic SaaS, they had dozens of tenants paying them, and the public face of all that effort was a page they’d rather not link to. Nobody wakes up wanting to redesign a directory page. They just want one they’re not apologetic about.
So Tendir Pro is exactly that — the directory you’d actually put on your homepage.
What I built
Three things, all aimed at turning a list into a marketplace.
A redesigned search hero. The search is the front door, so it’s the first thing I rebuilt. A proper hero with search front and centre, filters that read like a marketplace and not a form, and results that update on a clean full page reload rather than fighting the user mid-type. It sets the tone immediately: this is somewhere you shop for a business, not somewhere you query a table.
Switchable grid, list, and map views. Different people browse differently. Someone looking for the nearest clinic wants a map. Someone comparing salons wants a scannable grid of photos. Someone who already knows roughly what they want wants a dense list. So all three are first-class, switchable on the fly, sharing one result set. The map view in particular changes the feel of the whole thing — suddenly the directory is spatial, and “what’s near me” becomes the obvious question to ask it.
A fully redesigned landing page for every tenant business. This is the part I’m most attached to. In the stock experience, an individual business doesn’t really get a home of its own. Tendir Pro gives every tenant a proper landing page — services, hours, location, media, the things that actually make someone press “book.” It turns each business from a row in a list into a destination.
The engineering underneath
A pretty directory that buckles under load isn’t a product, it’s a demo. The harder half of Tendir Pro was making search fast on a real platform with real data, and that’s where most of the work went.
I profiled the search path on a live site in production — a directory with real tenants, real keywords, real traffic — rather than trusting a clean local box to tell me the truth. Two things showed up immediately.
The first was a classic N+1. For every business in the results, the code went back to the database several times — locations, schedule, media, top services, business type, the tenant record itself — so the query count grew in lockstep with the number of results. Eleven results meant dozens of queries; thirty-seven results pushed it to roughly 235. That’s the kind of cost that’s invisible on your laptop with three test tenants and brutal on a platform that’s actually succeeding. The more popular the directory got, the slower it got — the worst possible direction for that curve to point.
The second was the search join itself. The keyword table backing search was being read with a full scan, and the join degraded into a Block-Nested-Loop — the database walking rows in a loop because it had no index to jump straight to matches — with the grouping on top spilling into a temporary table and a filesort. All the slow-query greatest hits in one statement.
Worth naming the structural reason caching didn’t quietly save me here: a whole class of WordPress plugins run their data access as raw $wpdb queries, which sail right past the WordPress object cache. So even with a fast cache layer sitting in front of the site, these reads weren’t being served from it — every search genuinely hit the database, every time. The performance had to be real, not papered over.
For the fix I started where the risk was lowest and the proof was cleanest: targeted indexes. I added indexes on the keyword join columns and a composite index matching the status-and-tenant filter on the landing pages. On those tables the change applied instantly. The result was clean to verify — the problem join went from a full scan with a Block-Nested-Loop over hundreds of rows to a simple ref lookup hitting a handful, the temporary table and filesort disappeared entirely, and the search dropped from around 62ms to around 35ms. Roughly a 40% cut for an afternoon of careful index work and zero behaviour change. The kind of fix I trust on a production database.
I deliberately stopped there, and I want to be straight about why: the bigger wins live in code I’d be changing, and I’d rather ship a low-risk improvement today than gamble on a riskier one. The deferred work is mapped out. First, collapse the N+1 by batching those per-row lookups into IN() queries before the loop, which should take ~235 queries down to a dozen or so. Second, a transient cache around the assembled result set, keyed on the normalized search parameters — and crucially, at the caching layer I actually own inside the plugin, so I’m not fighting the raw-query problem, I’m sidestepping it. Date and availability search is its own beast and gets the same gate-and-cache treatment when I get there.
Who it’s for, and the outcome
Tendir Pro is for Booknetic SaaS platform owners — the people who’ve built a booking business and want a directory that earns its place on the homepage instead of hiding in a footer. The outcome is a directory customers actually want to browse and book from: a search that feels like a marketplace, three ways to look at the same businesses, a real landing page per tenant, and search that holds up when the platform grows instead of punishing success.
Honestly
The redesign was the fun part; the performance work was the part that makes it a product I’ll stand behind. I’m not pretending it’s finished — the index work was the responsible first move, and the batching and caching are real, scoped next steps, not vague someday-maybes. What I’m confident about is the shape of it: a directory that looks like somewhere you’d want to be, backed by a search path I understand all the way down to the query plan. That’s the version I’d put my name on, which is exactly why I did.