WooCommerce SEO: Fix What WordPress Gets Wrong by Default
WooCommerce ships defaults that create SEO problems on day one: crawlable filter URLs, an unmanaged tag taxonomy, indexable checkout pages and duplicate Product schema. Here is what to change, where, and what breaks if you get it wrong.
Quick answer
WooCommerce SEO starts with fixing defaults, not adding content. A fresh install ships crawlable attribute and filter URLs, an unmanaged product tag taxonomy, indexable cart and checkout pages, and a Product schema block that often collides with your SEO plugin’s. Fix those six defaults first. They cost nothing, take an afternoon, and decide whether anything you publish later can rank.
Most WooCommerce SEO advice starts with keyword research for product descriptions. That is the wrong end of the store. WooCommerce is a plugin that adds custom post types, four taxonomies and five system pages to WordPress, and every one of those defaults was chosen to make a shop function on install day, not to make it rank.
So a brand new store is already generating URLs nobody wants indexed, emitting structured data that may conflict with whatever SEO plugin gets installed next, and firing an AJAX request on pages that have no cart on them. None of that shows up as a red light in a plugin’s content score, which is why stores carry these problems for years while the owner rewrites product copy.
Below is what to change, the mechanism behind each problem, the exact admin path or filter, and what breaks if you change it carelessly. TopTut sells no plugins, no themes and no store audits, so there is nothing at the end of this to buy.
What WooCommerce does badly by default
WooCommerce’s defaults create four categories of problem: URL bloat, index bloat, duplicate structured data, and per-request overhead that shows up as slow category pages. They are all fixable in settings or with a few lines in a functionality plugin, and none of them require a paid tool.
The order matters. If your crawl budget is being spent on filter permutations and tag archives, adding twenty new product pages does not help, because the new pages queue behind the junk. Get the crawlable surface under control first, then publish. The same sequencing logic runs through our ecommerce SEO checklist, which covers the platform-agnostic version of this work.
The six defaults that hurt your WooCommerce SEO
These six ship enabled on every install, and each has a mechanism worth understanding before you touch it. Three are worth changing on nearly every store, two depend on your catalogue, and one is worth changing far less often than people think.
1. The /product/ and /product-category/ permalink bases
WooCommerce registers products under a /product/ slug and categories under /product-category/, and both are changed at Settings > Permalinks, per the official WooCommerce permalinks documentation. The product base offers Default, Shop base, Shop base with category, or a custom base; the category and tag bases sit in the Optional section below.
The honest position: on a new store, set these before launch and make them short. /shop/ or a bare category base reads better and puts your keyword closer to the root. On a store that has been live and ranking for two years, changing them is usually not worth it. You are rewriting every product and archive URL, relying on 301s to carry equity, and buying a re-crawl of your entire catalogue in exchange for removing one path segment. Google has never suggested that segment is a ranking factor.
One genuine trap: if you pick “Shop base with category” and your products sit in several categories, WooCommerce has to choose which category appears in the URL. As of WooCommerce 10.5 that choice changed to prefer the deepest category in the hierarchy rather than the lowest parent term ID, which can silently move product URLs on existing stores. Woo’s canonical redirect handling issues 301s automatically, but you want to know it happened rather than discover it in a crawl report.
2. Attribute and filter URLs generating crawlable duplicates
This is the single biggest source of index bloat on WooCommerce stores. Global attributes registered under Products > Attributes have an “Enable archives” checkbox, and ticking it creates a public archive at a URL like /size/medium/. Layered navigation widgets and most filter plugins then generate query-string URLs such as /shop/?filter_colour=blue&filter_size=medium, and every combination is a distinct crawlable URL serving near-identical content.
The arithmetic is unforgiving. Worked example, assumptions stated: a store with four filterable attributes carrying six values each. Filters are independently combinable, so the number of distinct filter states is 7 x 7 x 7 x 7 (six values plus “unset” per attribute) = 2,401 URLs per category archive. Multiply by twenty categories and pagination and you are asking Googlebot to crawl tens of thousands of pages to reach a few hundred products.
Leave attribute archives off unless a specific attribute has real search demand behind it, in which case enable that one attribute and treat its archive as a landing page with its own copy. For filter query strings, the reliable fix is a noindex, follow robots meta on any URL carrying a filter parameter, applied by your SEO plugin’s archive rules or a small conditional in your theme.
Watch out
Do not solve filter bloat with a robots.txt disallow. A blocked URL cannot be crawled, so Google never sees the noindex on it and can still list the URL from links alone. Robots.txt controls crawling; the robots meta tag controls indexing. You need the second one here.
3. Shop, cart, checkout and my-account
Of the four system pages WooCommerce creates, only the shop page belongs in the index. Cart, checkout and my-account are session-specific, thin when empty, and useless as entry points; they should carry noindex, follow and stay out of the XML sitemap. Woo assigns these pages under WooCommerce > Settings > Advanced, and the robots directive is set per page in your SEO plugin’s meta box.
The shop page is where people overcorrect. It is a real category-level page that frequently ranks for brand-plus-category queries, and noindexing it because “it is just a product listing” throws away a page with internal links pointing at it from every menu. Keep it indexable, give it an intro paragraph of actual copy above the grid, and let it work.
4. Product tags, the unmanaged second taxonomy
Product tags are a fully public taxonomy that most stores populate accidentally and never prune. A store owner tags a jacket “waterproof”, “rain”, “outdoor” and “waterproof jacket”, and WooCommerce dutifully creates four archives, two of which list the same single product and one of which competes directly with a product category of nearly the same name.
The mechanism that hurts is not the duplicate content itself but the dilution: internal links spread across near-identical archives, and Google choosing which one to show.
Default position: noindex the entire product_tag taxonomy and remove it from the sitemap. Every mainstream SEO plugin has a taxonomy-level switch for this. Reverse it only for tags you have deliberately built into landing pages with their own copy.
5. Variable products and thin variation URLs
Variable products append attribute query strings to the parent URL, producing addresses like /product/hoodie/?attribute_pa_colour=blue that render essentially the parent page with one dropdown preselected. Woo canonicalises these to the parent, which is correct behaviour, but link-building plugins, share buttons and internal “shop this colour” links routinely publish the variation URL, and once it is linked it gets crawled.
Confirm the canonical is actually pointing at the parent by loading a variation URL and reading the rel="canonical" in the source. If variants are genuinely distinct products with their own demand, promote them to standalone simple products with real URLs and real copy rather than trying to make a query string rank.
6. Pagination on category archives
Paginated category URLs should be indexable and self-canonical, and the common error is canonicalising every page back to page one. That tells Google page two is a duplicate of page one, so it stops treating page two as a crawl path, and the products only linked from page three onward lose their strongest internal link source.
Google retired support for rel="next" and rel="prev" as an indexing signal years ago, so the practical setup is simple: each paginated page canonical to itself, keep it crawlable, and make sure a deep product is reachable in three clicks or fewer. If your category has forty pages, the real fix is subcategories, not pagination tuning.
Settings and fixes, in one table
Every fix above, with the admin path or hook and the risk of getting it wrong. Work down it on a staging copy, and crawl before and after.
| Default | What goes wrong | Where to change it | Risk of changing it |
|---|---|---|---|
Product base /product/ | Generic segment on every commercial URL | Settings > Permalinks > Product permalinks | On a live store, rewrites every product URL and needs a full 301 map |
Category base /product-category/ | Long low-value segment on your best archives | Settings > Permalinks > Optional > Product category base | Same as above; every archive URL changes at once |
| Attribute archives enabled | Public /colour/blue/ archives with no copy | Products > Attributes > edit attribute > Enable archives | Disabling removes any attribute page that already ranks |
| Filter query strings crawlable | Combinatorial duplicate URLs per category | SEO plugin archive rules, or a robots meta conditional on filter params | A robots.txt block instead of noindex leaves URLs listed but uncrawlable |
| Cart, checkout, my-account indexable | Thin session pages in the index and sitemap | Per-page robots setting in your SEO plugin | Noindexing the shop page too loses a page that often ranks |
product_tag archives public | Duplicate taxonomy competing with categories | SEO plugin taxonomy settings, noindex plus sitemap exclusion | Tags used in navigation become dead-end links |
| Paginated archives canonical to page 1 | Deep products lose their internal link path | SEO plugin archive settings; set self-canonical | Making page 2+ noindex orphans products entirely |
| Woo Product JSON-LD always output | Two Product blocks when an SEO plugin also emits one | woocommerce_structured_data_product filter | Removing both leaves you with no Product markup at all |
Structured data: what Woo emits, and the double-schema problem
WooCommerce core emits its own JSON-LD without any plugin, through the WC_Structured_Data class, covering Product with nested Offer, plus BreadcrumbList, WebSite and Organization on the relevant templates. It pulls price, currency, stock status, SKU, ratings and reviews from the product object, so it is generally accurate about availability.
What it omits is the merchant-listing detail Google increasingly wants: GTIN, MPN and brand are not populated unless you map them, shipping and return policy properties are absent, and it does not emit variant relationships. Google’s product snippet documentation lists name plus at least one of offers, review or aggregateRating as the requirement, and Woo clears that bar; it is the recommended properties where the gaps sit.
Why two Product blocks is a real problem
Install Rank Math, Yoast WooCommerce SEO or SEOPress Pro and you now have two independent systems writing Product markup into the same page. Google does not error on this, but it does have to pick, and the block it picks may be the one with the stale price, the missing availability value, or a rating count from a plugin that reads reviews differently. Both blocks validating individually tells you nothing about which one is being used.
Google’s guidance is that product rich results support pages focused on a single product or its variants, and that markup should be in the initial HTML. Two competing descriptions of that single product is exactly the ambiguity you want to remove.
How to tell which one is winning, and how to pick
View source on a product page and search for "@type":"Product". If it appears twice, you have the conflict. Then run the URL through Google’s Rich Results Test and compare the parsed values against both blocks in your source; whichever set of values the test reports is the one Google is reading.
Pick one emitter and disable the other. If your SEO plugin adds brand, GTIN and shipping properties, keep it and switch off Woo’s block with a one-line filter. If you are on free plugin tiers, keep Woo’s output, because it is closer to the source of truth on price and stock.
// Stop WooCommerce emitting its own Product JSON-LD, so only
// your SEO plugin's Product markup remains on the page.
add_filter( 'woocommerce_structured_data_product', '__return_empty_array' );
Which SEO plugin for a WooCommerce store
For most stores the free tier of any of the three main plugins is enough, because everything in the defaults section above is configurable for free. Paid tiers buy you product-specific schema fields, bulk editing and redirect management, which start mattering somewhere in the hundreds of SKUs.
| Plugin | Entry paid price | What the free tier covers on a store | What paying adds for WooCommerce specifically |
|---|---|---|---|
| Rank Math | PRO at EUR 95.88/year, billed annually | Auto canonicals, redirections, sitemap controls, 18 predefined schema types, Search Console integration | The WooCommerce SEO module, listed across the PRO, Business and Agency tiers |
| Yoast | Yoast WooCommerce SEO at USD 178.80/year ex VAT, with Yoast SEO Premium included | Robots meta and sitemap control per post type and taxonomy, breadcrumbs, canonical management | Product schema with identifiers, sitemaps that skip cart, checkout and filter pages, product detail checks |
| SEOPress | PRO at USD 49/year for one site, USD 59 for five, USD 149 unlimited | Content analysis with unlimited keywords, standard on-page controls | Primary product category, product category URL cleanup, Enhanced Ecommerce tracking, removes Woo generator tags |
The clear position: SEOPress PRO is the best value on price alone, and its unlimited-site tier is the cheapest way to cover a portfolio. Rank Math‘s free tier is the most generous of the three and is genuinely sufficient for a store under a few hundred products. Yoast WooCommerce SEO is the most expensive and the most conservative, which is a fair trade if you want the least surprising behaviour. Whichever you install, resolve the double-schema conflict on day one.
The performance problems unique to WooCommerce
WooCommerce’s headline performance issue is cart fragments, an AJAX call that historically ran on every page load whether or not a cart was visible. The WooCommerce developer documentation confirms the script uses the admin-ajax API to refresh the cart without a page reload, that before WooCommerce 7.8 it loaded on all pages by default, and that on high-traffic stores this had a severe impact on server load and responsiveness.
The mechanism is what makes it expensive: admin-ajax requests bypass page caching entirely and boot WordPress fresh each time, so a page delivered instantly from cache can still be waiting on an uncached PHP request behind it. Woo now limits the script to pages that render a cart widget, and recommends either the Mini-Cart block, which does not use the fragments API, or a conditional dequeue.
// Load cart fragments only where a cart actually appears.
add_action( 'wp_enqueue_scripts', function () {
if ( is_woocommerce() || is_cart() || is_checkout() ) {
return;
}
wp_dequeue_script( 'wc-cart-fragments' );
}, 11 );
The second rule is absolute: full-page caching must exclude cart, checkout, my-account and any URL carrying add-to-cart. Serve one shopper a cached copy of another shopper’s cart and you have a support incident, not an SEO problem. Every serious caching plugin ships these exclusions by default; verify them rather than assuming, particularly after switching hosts.
Third, catalogue size shows up as slow category pages long before it shows up as a slow product page. A product archive query joins posts, postmeta, term relationships and the product lookup tables, and once postmeta has grown through years of orders and abandoned variations, that query slows and every category template slows with it. If your category pages feel heavier than your product pages, that is where to look. The TopTut WordPress health check tool is a reasonable starting point for separating server-side slowness from front-end weight.
What changes at thousands of SKUs
Past roughly two thousand products, WooCommerce stops being a settings problem and becomes a database problem. The admin gets slow before the front end does, and the first symptom is usually the Products list screen or a bulk edit timing out.
- Keep the product lookup tables populated. WooCommerce maintains them so reporting and filtered queries stop hammering postmeta; a partial rebuild after an import leaves wrong counts and slow archives.
- Turn off what you do not use. Product reviews, coupons, the legacy REST endpoints and unused analytics reports all cost queries on pages that never display them.
- Move order storage to high-performance order tables if you have not already. Orders living in postmeta are the single largest contributor to a bloated table that slows unrelated product queries.
- Audit orphan variations after every import. Failed imports leave variation posts with no parent, and they count against every query that touches the products table.
The out-of-stock question comes up constantly at this scale. Keep discontinued and out-of-stock products live with their URL intact and set the schema availability to OutOfStock, Discontinued or BackOrder as appropriate, all of which Google lists as supported values. A product page that has accumulated links and rankings over three years is an asset; deleting it converts that asset into a 404 and hands the query to a competitor. Add a visible in-stock alternative on the page and you keep the traffic and convert some of it.
WooCommerce versus a hosted platform on SEO
WooCommerce wins on control and loses on defaults, and that trade is the whole comparison. Hosted platforms give you a faster, safer baseline that you cannot fully override; WooCommerce gives you total control over a starting point that is worse.
| Dimension | WooCommerce | Typical hosted platform | Who wins |
|---|---|---|---|
| URL structure control | Any structure you want, including removing bases entirely | Fixed prefixes such as /products/ and /collections/ that cannot be removed | WooCommerce |
| Structured data control | Full control via filters; also the source of the double-schema conflict | Theme-level markup, editable but constrained by the template language | WooCommerce |
| Page speed baseline | Depends entirely on host, theme and plugin stack | Global CDN and tuned stack out of the box | Hosted |
| Redirect management | Plugin-dependent; unlimited rules, but you own the maintenance | Built in, usually with a bulk CSV import | Roughly even |
| Server log access | Full access on any decent host; real crawl analysis is possible | Usually unavailable, so crawl budget work is guesswork | WooCommerce |
| Faceted navigation control | You must build the noindex rules yourself | Constrained by design, so less rope to hang yourself with | Hosted |
| Maintenance burden | Updates, PHP versions and plugin conflicts are yours | Handled by the vendor | Hosted |
Log access deserves more weight than it usually gets: seeing which URLs Googlebot actually spent its requests on is the difference between fixing crawl waste and guessing at it, and that data is unavailable on most hosted platforms. If you are weighing the move in either direction, our rundown of Shopify alternatives covers the commercial side, and the limitations of WordPress is the honest version of what you take on by self-hosting.
Mistakes that quietly cost stores rankings
Four errors account for most of the self-inflicted damage on WooCommerce stores, and all four are done by people trying to help.
- Deleting discontinued products. The seasonal clear-out that removes 300 SKUs removes 300 URLs, their backlinks and their rankings. Set them out of stock, keep the page, redirect only when a genuine replacement exists.
- Noindexing category archives that rank. Category pages are usually a store’s best commercial pages because they match the plural query intent. Noindexing them as “thin” removes the pages that convert.
- Letting two systems emit Product schema. Discussed above, and worth repeating because it survives site redesigns. Every time someone swaps SEO plugins without disabling the new one’s schema output, the conflict comes back.
- Blocking add-to-cart URLs in robots.txt too broadly. A rule like
Disallow: /*?add-to-cart=is defensible, but a broader wildcard on query strings will also block your filter URLs, your paginated archives and sometimes your assets. Blocking CSS or JS also breaks rendering. Test every robots rule in Search Console’s robots.txt report before shipping it.
The verdict, by store size
What you should actually do depends almost entirely on how many products you have and how long the store has been live.
Under 100 products, new store. Set your permalink bases before launch, install Rank Math free, noindex product tags and the three account pages, leave attribute archives off, and let WooCommerce keep its own Product schema. That is the whole job. Spend the rest of your time on product copy and on the store foundations covered in our guide to building a WordPress ecommerce website.
100 to 2,000 products, established store. Do not touch the permalink bases. Fix the index bloat instead: crawl the site, find the filter and tag URLs in the index, apply noindex, and resolve the schema conflict. SEOPress PRO at USD 49 for one site is the sensible paid upgrade if you want bulk editing and redirects without a large bill.
Over 2,000 products. Treat this as a database and crawl-budget project. Migrate order storage, keep the lookup tables healthy, segment sitemaps, and pull server logs to find out where Googlebot is actually spending requests. Paid plugin features are worth it here purely for bulk operations, and anything deeper than settings is engineering time rather than another plugin.
The through-line at every size is the same. WooCommerce will not stop you doing the wrong thing, and it will not tell you it is happening. The defaults are the first place to look, and for most stores they are also the last place anyone looked.
Frequently asked questions
Should I remove /product/ from my WooCommerce URLs?
On a store that has not launched yet, yes, set a shorter base at Settings then Permalinks before any URL is indexed. On a store that has been live and ranking for a year or more, no. You would rewrite every product URL, rely on 301 redirects to carry equity, and buy a full re-crawl in exchange for removing one path segment that Google has never treated as a ranking factor.
How do I stop WooCommerce filter URLs being indexed?
Apply a noindex, follow robots meta tag to any URL carrying a filter query parameter, using your SEO plugin’s archive rules or a conditional in your theme header. Do not use a robots.txt disallow instead. A blocked URL cannot be crawled, so Google never reads the noindex on it and can still list the address from links pointing at it.
Does WooCommerce add product schema without a plugin?
Yes. WooCommerce core emits JSON-LD through its WC_Structured_Data class, covering Product with a nested Offer, plus BreadcrumbList, WebSite and Organization. It reads price, currency, stock status, SKU and reviews from the product object. It does not populate GTIN, MPN or brand unless you map them, and it does not output shipping or return policy properties.
Which Product schema wins when two plugins output it?
You cannot tell from validation alone, because both blocks can validate independently. View source, search for the Product type, and if it appears twice run the URL through Google’s Rich Results Test. The values the test reports are the ones Google is reading. Then disable one emitter so only a single description of the product remains in the page.
Is the free version of an SEO plugin enough for WooCommerce?
For a store under a few hundred products, usually yes. Every fix in this article, including noindexing tags and account pages, sitemap control and canonical management, is available in the free tiers of Rank Math, Yoast and SEOPress. Paid tiers buy product schema identifier fields, bulk editing and redirect management, which start earning their price in the low thousands of SKUs.
Should I delete products that are out of stock permanently?
No, in almost every case. Keep the URL live and set the schema availability value to OutOfStock, Discontinued or BackOrder, all of which Google supports. A product page that has collected links and rankings over several years is an asset, and deleting it turns that asset into a 404. Add a visible in-stock alternative on the page instead.
Why are my WooCommerce category pages slower than product pages?
Category archives run a query that joins posts, postmeta, term relationships and the product lookup tables, so they feel the weight of a bloated database before single product pages do. Years of orders and abandoned variations stored in postmeta are the usual cause. Moving order storage to the high-performance order tables and clearing orphan variations is where to start.
Should paginated category pages be noindexed?
No. Keep page two onward indexable and self-canonical. Canonicalising every paginated page back to page one tells Google those pages are duplicates, so it stops using them as a crawl path and products listed only on later pages lose their strongest internal link. If a category runs to dozens of pages, the real fix is subcategories.
1 response