**TL;DR.** PLP SEO has three rules. (1) Canonical the base category and bless specific filter combinations that map to real search queries. (2) Noindex arbitrary facet combinations and search results to control crawl budget. (3) Render server-side and emit CollectionPage schema. The "blessed facet" pattern is the strategic lever for capturing long-tail queries.

## Why category SEO matters

Category pages capture the highest-intent commercial queries:

- "leather bags" (1.2M monthly Google searches globally)
- "brown leather messenger bag" (40k monthly)
- "vegan leather laptop bag for women" (8k monthly)

Each of these is a category-shaped query. Ranking the right URL for each is the difference between mid-funnel and top-of-funnel traffic.

## URL hierarchy

Recommended structure:

```
/categories/leather-bags                       (parent)
/categories/leather-bags/messenger             (child)
/categories/leather-bags/messenger/work        (grandchild — only if necessary)
```

Or with locale prefix:

```
/en/categories/leather-bags
/de/categorien/leder-taschen
```

Limit depth to 3 levels. Beyond that, navigation becomes brittle and link equity dilutes.

## The faceted navigation problem

A typical PLP has:

- 5 color filters
- 4 size filters
- 8 price-range filters
- 3 sort orders
- N pages of pagination

Combinations: 5 × 4 × 8 × 3 × N = 480N URLs per category. With 50 categories, you have 24,000N URLs from facet combinations alone. Crawl budget destroyed.

The fix:

| URL pattern                                         | Indexing decision         |
| --------------------------------------------------- | ------------------------- |
| `/categories/leather-bags`                            | Index                     |
| `/categories/leather-bags?page=2`                     | Index, self-canonical     |
| `/categories/leather-bags?sort=price-asc`              | **Canonical to base** + noindex |
| `/categories/leather-bags?color=brown`                 | Depends — see "blessed facets" |
| `/categories/leather-bags?color=brown&size=m`           | Canonical to base + noindex |
| `/search?q=leather+bag`                                | **Noindex** always        |

## Blessed facets

Some filter combinations map to real search queries that users type. Those deserve their own indexable URL.

How to decide what to bless:

1. **Crowdsourced query data**: Google Search Console → Queries report. Filter by category page. Look for queries that imply a specific facet ("brown leather bag", "small leather bag").
2. **Search-volume data**: Keyword tools confirm "brown leather bag" gets searched. "Vintage faded leather bag size medium between $80 and $120" does not.
3. **Conversion data**: which filter combinations lead to purchases? High-converting combos with search volume are blessed candidates.

Blessed facet implementation:

```ts
// Pseudocode
interface BlessedFacet {
  facet: { name: string; value: string }; // e.g., { name: "color", value: "brown" }
  category: string; // e.g., "leather-bags"
  seoTitleTemplate: string; // e.g., "Brown Leather Bags — {brand} Collection"
  seoDescription: string;
  ogImageUrl?: string;
  noIndex?: boolean; // override
}
```

For a blessed facet, render at a clean URL with optimized metadata:

```
URL:     /categories/leather-bags/color-brown
Title:   Brown Leather Bags | Acme Leather Goods
Meta:    Discover our collection of brown leather bags — handcrafted from full-grain leather. Free shipping on orders over $50.
Canonical: self
Index: yes
```

Unblessed combinations (e.g., color=brown + size=medium + sort=price-asc):

```
URL:     /categories/leather-bags?color=brown&size=medium&sort=price-asc
Title:   Leather Bags | Acme Leather Goods  (fall back to base)
Canonical: /categories/leather-bags
Index: no
```

## Search query URLs

Search results almost always:

- Map to many similar URLs.
- Have low intrinsic content quality (just a list of products).
- Are highly variable (every typo creates a new URL).

Noindex them:

```html
<meta name="robots" content="noindex, follow" />
```

`follow` because internal links from search pages still pass equity.

## Pagination

The 2026 best practice:

- Each page (page 2, 3, ...) self-canonicals.
- `rel="next"` and `rel="prev"` are deprecated but still parsed as hints — emit them if it's easy.
- The full content of each page must be server-rendered.
- Total result count and current page visible in the H1 or above the fold for user clarity.

```html
<head>
  <link rel="canonical" href="https://example.com/categories/leather-bags?page=2" />
  <link rel="prev" href="https://example.com/categories/leather-bags" />
  <link rel="next" href="https://example.com/categories/leather-bags?page=3" />
</head>
```

## Server-rendering

Category pages must render their content server-side. Client-rendered React PLPs where you fetch products in `useEffect` get a near-empty HTML response from Google's crawler.

Use Next.js Server Components (or equivalent framework's SSR/SSG) for the product grid. Pagination, sort, and filters can be Suspense boundaries that stream after the static shell.

## CollectionPage schema

Wrap the PLP in `CollectionPage` with embedded `ItemList`:

```json
{
  "@context": "https://schema.org",
  "@type": "CollectionPage",
  "name": "Leather Bags",
  "description": "Browse our handcrafted leather bag collection.",
  "url": "https://example.com/categories/leather-bags",
  "mainEntity": {
    "@type": "ItemList",
    "itemListElement": [
      {
        "@type": "ListItem",
        "position": 1,
        "url": "https://example.com/products/brown-messenger-bag"
      },
      {
        "@type": "ListItem",
        "position": 2,
        "url": "https://example.com/products/black-leather-tote"
      }
    ]
  },
  "breadcrumb": {
    "@type": "BreadcrumbList",
    "itemListElement": [
      { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.com" },
      { "@type": "ListItem", "position": 2, "name": "Categories", "item": "https://example.com/categories" },
      { "@type": "ListItem", "position": 3, "name": "Leather Bags", "item": "https://example.com/categories/leather-bags" }
    ]
  }
}
```

For blessed facet URLs, also emit `CollectionPage` with the facet-specific title/description and an `ItemList` of the filtered products.

## Title and description per blessed facet

The titles and descriptions are how blessed facets win their queries.

Base category:

```
<title>Leather Bags | Acme — Handcrafted Italian Leather</title>
<meta name="description" content="Browse our collection of handcrafted leather bags from Italy. Full-grain materials, solid brass hardware, free shipping over $50.">
```

Blessed facet (color=brown):

```
<title>Brown Leather Bags | Acme — Handcrafted Italian Leather</title>
<meta name="description" content="Discover handcrafted brown leather bags from Italy. Full-grain materials, solid brass hardware, free shipping over $50.">
```

Blessed facet (color=brown + style=messenger):

```
<title>Brown Leather Messenger Bags | Acme</title>
<meta name="description" content="Browse our brown leather messenger bag collection. Handcrafted in Italy with full-grain leather and solid brass hardware. Free shipping over $50.">
```

## How Ordiko handles category SEO

- `/categories/{slug}` URL pattern with hierarchy support.
- `BlessedFacet` table per store: facet, category, SEO template overrides.
- Blessed facets render at clean URLs (`/categories/leather-bags/color-brown`); unblessed canonical to base with noindex.
- Search query pages auto-noindex.
- Pagination self-canonicals.
- CollectionPage + ItemList + Breadcrumb schema on every PLP.
- Server-rendered with React Server Components.

## FAQ

**Should I noindex faceted URLs entirely?**
Noindex unblessed combinations (arbitrary filter + sort combos). Allow indexing of base category and whitelisted 'blessed' facets that map to real search queries. The whitelist is the strategic lever — it's how 'leather bags', 'brown leather bags', 'brown leather messenger bags' each get their own ranking opportunity.

**How do I decide which facets to bless?**
Cross-reference your filter values with search-query data (Google Search Console + your own search log + keyword tools). Filter values that match real searches become blessed. Arbitrary value combinations stay noindex.

**What about color + size + price combinations?**
These compound. 'brown leather bag' is searchable; 'brown leather bag size medium under $200' is not. Bless single-attribute and dual-attribute combos at most; noindex 3+ attribute combos.

**How does Ordiko handle facets?**
Ordiko's seo settings expose a blessedFacets array per store. Each entry specifies the facet (e.g., color=brown), its SEO template (title, description, OG image override), and emits a clean URL like /categories/leather-bags/color-brown that gets indexed. Other combinations noindex automatically.
