Programmatic SEO for a WooCommerce Store's Filter Pages
Turning a tire retailer's WooCommerce attribute filters into thousands of indexable landing pages: dynamic titles & meta, pretty URLs, and careful index control.
- WordPress
- WooCommerce
- PHP
- WPML
- Technical SEO
The opportunity
A Ukrainian tire e-commerce store on WooCommerce had a classic long-tail problem.
People don’t search for “tires” — they search for “winter tires 205/55 R16”, i.e. a
specific combination of season, width, profile and diameter. The store already had all
of that as WooCommerce product attributes and a filter plugin that let visitors narrow
down products. But those filtered views were invisible to Google: ugly query-string
URLs, a generic shop <title> on every combination, and no strategy for which of the
millions of possible filter combinations should actually be indexed.
The goal: turn the valuable filter combinations into real, rankable landing pages — without letting the near-infinite combinatorial space of filters flood the index with thin, duplicate junk.
What I built (all in a child theme, ~36 focused modules)
-
Dynamic titles & meta descriptions from the filter state. On a filtered shop URL, PHP reads the active filters (manufacturer, season, profile, width…) and builds a human, keyword-rich
<title>and meta description on the fly — “Winter tires 205/55 R16 — buy in Ukraine” — including translating attribute slugs into proper words (zymovi→ «зимові») and appending brand, price-from and delivery text. Every meaningful combination gets its own tailored snippet instead of the shop default. -
Pretty, crawlable URLs. Custom
rewrite_rules_arrayrules turn query-string and/shop/...paths into clean, hierarchical ones like/shyny/{category}/and a segmented/shynu/{season}/{manufacturer}/{width}/{profile}/{diameter}/structure — the kind of URL that both users and search engines trust. -
Deliberate index control — the hard part. Left alone, filters generate an effectively infinite URL space, which is an SEO disaster. So there’s a rule: pages with 4 or more simultaneous filters get a
noindextag (too specific, too thin, cannibalizing). But the chosen high-value landing combinations get theirnoindexactively stripped via output buffering, so exactly the pages worth ranking are the ones Google is allowed to keep. -
Pagination done right.
rel="prev"/rel="next"links plus “Page N” appended to titles and meta descriptions, so paginated category pages don’t fight each other as duplicates. -
Canonical dedup on the shop page, and hreflang corrections for the bilingual (Ukrainian / Russian) setup, patched at the output-buffer level where the SEO plugin and WPML disagreed.
-
Per-language dynamic H1s rebuilt from the selected filters, so a filtered page’s visible heading matches its title and the user’s language.
The result
Instead of one invisible shop page behind a query string, the store exposed a structured, controllable set of landing pages mapped to how people actually search for tires — with strict guardrails so only the pages worth indexing were indexed. It’s the difference between “we have a filter” and “our filters are our long-tail SEO.”
The engineering takeaway
None of this was a plugin I could install — it’s the seam between three of them
(WooCommerce, a filter plugin, and an SEO plugin), and that seam is exactly where
custom code earns its keep. Everything lives in the child theme as small,
single-responsibility modules (one file removes the archive-title prefix, one handles
canonicals, one builds the dynamic title…), so the SEO logic is readable and auditable
instead of buried in a 2000-line functions.php.