TDM Insights TDM Insights SEO & AI Advisory
Case study · Artisan retail · Bala, Muskoka

Eight workstreams. One of them was the website.

Cacao Boys makes hand-painted bonbons onsite in Bala. Their site looked pleasant, could not be read by a search engine, could not be quoted by an assistant, and took 21 seconds to show a product on a phone. Replacing it took ten days.

10
Days from kickoff to the new site going live. The project record, day 0 to day 10.
183
Published products carried across and recategorised, counted in the live store.
79 / 79
URLs with search history kept alive through the platform move.
8
Workstreams inside one rebuild, itemised in full at the end of this page.
Delivery

The build was ten days. The decision took longer.

The diagnostic recommended a patch and said plainly that none of this was a rebuild. Sixteen days later we withdrew that advice, because a page-builder runtime sets a ceiling that tuning does not reach. Recommending a larger piece of work after advising against it is uncomfortable, and it was the right call.

The diagnostic came first. The build began at kickoff, sixteen days later; day zero below is kickoff.
Day 0
Rebuild proposed, kickoff
Day 2
Whole site on staging
Day 7
Client review queue, 14 requests
Day 10
Live
Day 13
Measured

Whole-site v0.5 stood up on password-protected staging two days after kickoff. Everything after that was iteration against a live client review queue rather than a first draft.

Performance · mobile, median of three Lighthouse runs

The slowest page on the site became one of the fastest.

The product page is where the money is, and it was the worst page they had. A shopper on a phone waited 21.5 seconds to see the chocolate they had clicked. Bar length is load time, so shorter is faster.

Product page
Was21.5s · 33
Now4.2s · 80
Home
Was10.7s · 61
Now3.2s · 93
Custom boxes
Was6.8s · 62
Now4.0s · 87
About
Was7.6s · 63
Now5.1s · 74
Shop
Was7.3s · 63
Now5.3s · 74
Bonbons
Was5.8s · 67
Now5.3s · 73
MeasureOld siteLive site
Product page, desktop score4299
Shop and category, desktop score81 to 93100
Cumulative layout shift, all pagesnot measured0
Accessibility, range across pages79 to 9297 to 100

Shop and the bonbons category are the weakest live pages on mobile at 74 and 73. The heaviest single file on both is a 160KB third-party analytics tag; blocking it in a controlled test recovered roughly a quarter of a second. Reported as a lead, not as an excuse.

Brand and communications

A custom theme, with no page builder underneath it.

The photography was the strongest asset the business had, and it was sitting inside a stock theme that undercut it. BeTheme and Elementor were replaced with a purpose-built design system, and the shop's own language was rewritten around what it actually sells: painted edible art, made in Bala, bought as a gift.

Home · before
The old Cacao Boys homepage
Home · live
The rebuilt Cacao Boys homepage
Product · before
The old product page
Product · live
The rebuilt product page
Category page · live
A live category archive with its seasonal hero rotator and its own opening copy
Reviews wall · live
The Google reviews wall on the live homepage

Each category archive carries its own hero and its own opening copy rather than one generic line, so a shopper landing on Seasonal from search reads about seasonal chocolate. The hero images run on a seasonal rotator that shipped alongside the theme as a reusable plugin, so the shop can set up its own autumn and holiday takeovers without us.

The catalogue · 183 published products

The workstream that is easiest to underestimate.

A WooCommerce catalogue is a database, and this one had grown for three years without an owner: duplicated boxes, a merch tail longer than the chocolate range, and product images that cropped badly in the grid. It was the largest single workstream in the rebuild.

Confections56
Merch71
Dipped25
Bonbons21
Seasonal10
Custom boxes8

One square per product. Merch is the longest row in the catalogue: 71 t-shirts and hats against 112 chocolate products, which is the imbalance the category restructure had to solve.

135
Products given a written short summary and a long-form description in the shop's own voice.
175
Product images re-squared with adaptive padding so grid crops stop cutting the chocolate.
60
Nutrition labels reconciled against products, with a label-to-product map.
17
Question and answer pairs written and marked up for search and assistants.

Every bulk operation ran with a manifest and a one-command restore. The image work never overwrote an original: each squared file was imported as a new attachment and the product's thumbnail repointed, with the previous value captured first.

Commerce correctness

A setting can be switched on and still do nothing.

A checkout audit was not in the brief. Rebuilding the templates meant reading the store configuration, and in three places that configuration did not match what the site was telling customers.

Defect 01 · Shipping was never actually configured
The site said
Flat $15 shipping within Canada
The store did
Flat rates disabled.
Zones had empty regions,
so no rate could ever match.
Rebuilt as one Canada zone: free local pickup, $10 flat under $150, free over $150, calculated pre-tax. The advertised $15 existed only in copy.
Defect 02 · A free-shipping threshold that did not exist
The banner promised
Free shipping on orders of $100 or more
WooCommerce enforced
min_amount = 150
Shoppers were being offered a threshold the checkout would refuse. WooCommerce is now the single source of truth and the cart notice reads the live figure instead of hardcoding one.
Defect 03 · A pickup rule that silently never fired
The rule targeted
"Shipping - Flat Rate of $10 within Canada"
The store's method was named
"Flat-rate shipping (Canada)"
The plugin matches on an exact title string, so the date exclusion was enabled, looked correct in the admin, and had never once applied.

Also closed at cutover: card payments flipped from test to live and verified server-side, search-engine visibility re-enabled so canonicals resolved sitewide, and order confirmation emails fixed after they were found failing domain authentication.

The migration · Day 10, launch day

A platform move is where rebuilds quietly lose what they already had.

The redirect map was built from evidence rather than assumption, from three sources that each catch what the others miss.

Source 01
217

URLs the old site published, taken from its own sitemap rather than a crawl that could miss orphans.

Source 02
Crawl

Pagination, feeds and legacy category paths that were linked and live but never listed in the sitemap.

Source 03
16 mo

Search Console history, so the map was driven by what had earned a visit, not by what happened to exist.

That produced a 41-row map, of which ten rules run at the CDN edge and the rest are handled inside the theme. Six of the ten flatten the old /product-category/ base onto clean category URLs. The other four retire pages whose content moved: the old gallery folds into About, the menu into the cafe page, and /gifts-and-merch/ becomes /merch/, which carried more search impressions than any other redirect in the map.

Verified after cutoverResult
URLs with Search Console history still reachable79 of 79
Sitemap URLs requested individually, returning 200199 of 199
Sitemap URLs that redirect rather than resolve0
Legacy URLs still returning 404, none with traffic5, down from 10
Findability and AI visibility

For a local shop, being quotable is the same problem as being findable.

The old site ran without an SEO plugin, so it had no descriptions, no controlled titles and no structured data beyond what WooCommerce emits by default. Customers who ask an assistant where to buy chocolate near Bala had nothing to be pointed at.

SignalOld siteLive site
Meta descriptions0 sitewideUnique on every page
Pages with no H181 of 1500
Title lengthUp to 101 chars47 to 51 chars
Schema types per pageProduct only12 to 22
Google's Lighthouse SEO scoreNot comparable100 on every page

Answer-engine readiness on the category page

Seven signals, scored 0 to 100, before the change and after launch.

Answer-first structure
60 to 82
Extractable facts
68 to 80
Entities and definitions
85 to 88
Question coverage
55 to 55
Citations
40 to 40
Scannable formatting
82 to 86
Structured-data readiness
78 to 80

The site average moved from 34, the not-citable band, to 81. The bonbons category was the last page in the partial band and cleared it after one plain-language paragraph went in above the product grid. Question coverage did not move, because that signal only responds to an FAQ block, which the category and product pages still do not carry.

The manifest

Everything that shipped.

A rebuild is quoted as one line on an invoice. This is what the line contained.

Theme and front endDays 0 to 9
  • +Custom WordPress theme replacing BeTheme and Elementor
  • +Design-system tokens, type scale and component CSS
  • +Homepage: hero, collection grid, craft, events, visit, FAQ
  • +Shop archive with category tabs and per-category hero copy
  • +Product page redesign with spec panel and gallery
  • +Build-a-box builder skin across six box sizes
  • +Cart and checkout restyled inside the theme wrapper
  • +About, in-store cafe, events, contact and wholesale pages
  • +Mobile navigation, search panel and footer directory
  • +Seasonal hero rotator shipped as a reusable plugin
Catalogue and product dataDays 2 to 8
  • +135 products given a short summary and a long description
  • +Per-product SEO titles and meta descriptions
  • +Category restructure and shop tab reordering
  • +Assorted boxes merged into a single Custom Boxes category
  • +175 product images re-squared with adaptive padding
  • +Image alt text completed across the grids
  • +60 nutrition labels reconciled to products
  • +Allergen lines drafted for merchant verification
  • +Wholesale gating at a $300 and five-piece minimum
  • +Reversible manifests and one-command restores throughout
Commerce and configurationDays 4 to 10
  • +WooCommerce shipping zones and rates rebuilt
  • +Free-shipping threshold made a single source of truth
  • +Filter to hide the paid rate once free shipping qualifies
  • +Pickup-date rule repaired after silent failure
  • +Seasonal shipping pause with a dated re-enable
  • +Card payments switched from test to live and verified
  • +Order confirmation email authentication fixed
  • +Events and contact form delivery tested
Search, schema and answer enginesDays 3 to 13
  • +SEO plugin installed and configured from zero
  • +Unique meta description written for every page
  • +One H1 per page across the site
  • +Organization and Store entity graph on every page
  • +Product, Offer and Brand markup on product pages
  • +Cafe menu schema and AboutPage markup
  • +17 question and answer pairs written and marked up
  • +Answer-first opening copy on category archives
  • +Yoast sitemap replacing the WordPress default
Migration and hardeningDays 10 to 12
  • +Redirect map built from sitemap, crawl and search data
  • +Host move from SiteGround to Kinsta
  • +Edge redirect rules and theme-level legacy handling
  • +All 199 sitemap URLs verified at 200 after cutover
  • +72 orphaned staging tables dropped after backup
  • +Search-engine visibility re-enabled, canonicals restored
  • +Security pass closing a personal-data exposure
MeasurementBaseline, then day 13
  • +Baseline audit of the old site across 6 pages
  • +Full-page captures of both sites for comparison
  • +PageSpeed medians, mobile and desktop
  • +Seven-signal answer-engine audit, before and after
  • +Controlled third-party tag cost test
  • +Synchronised side-by-side scroll video, 8 pages
Total line items50
Method: Google PageSpeed Insights v5 (Lighthouse), 6 pages, mobile and desktop, median of 3 runs. TDM seven-signal answer-engine audit, 5 pages. Live inspection of headings, metadata and JSON-LD across 10 pages. All 199 sitemap URLs requested individually. Catalogue counts read from the live store. Lab data, point in time, measured three days after launch, so it carries no traffic or ranking claim yet. Measured, not modeled. Metrics current as of day 13.
Start with a diagnostic

A tune-up can become a rebuild. We tell you which, and why.

Every engagement opens with a diagnostic on a short call: the technical blockers capping your visibility, each with its fix, and an honest read on whether your platform can be tuned or needs rebuilding. Accessible hourly and fixed-fee arrangements, so the scope fits the business.

Book a free diagnosis

The deliverable. A diagnostic report: the blockers capping your visibility ranked by impact, each with a fix, the answer-engine gaps keeping you out of AI results, and a clear recommendation on optimize versus rebuild with the cost of each. Yours to execute, with us, or on your own.