Skip to content

Fix category chips: dead links, and the wrong category on the card - #205

Merged
ssavutu merged 2 commits into
mainfrom
fix/category-chip-slug
Aug 7, 2026
Merged

Fix category chips: dead links, and the wrong category on the card#205
ssavutu merged 2 commits into
mainfrom
fix/category-chip-slug

Conversation

@ssavutu

@ssavutu ssavutu commented Aug 7, 2026

Copy link
Copy Markdown
Member

Two defects behind Janine's screenshot of a men's lacrosse article showing under Columns. The second is what she reported; the first I found alongside it and is live right now.

1. Chips link to pages that don't exist

The chip is a link, and its target was derived from the category name alone via CanonicalizeSlug, independent of site_taxonomy:

/mens-basketball    200   ← the real subsection page
/men-s-basketball   404   ← what the chip linked to

Both basketballs and both soccers — the four apostrophe subsections — have had dead chips this whole time. Same apostrophe possessiveVariant already absorbs on the matching side; the link never got the same treatment. Nobody reported it because a chip is a small target and the article underneath works.

Now resolved through site_taxonomy, falling back to the derived slug so the value is never empty. A category that only reaches a section by alias — men's lacrosse after #199 — links to that section instead of nowhere.

Two things to review:

  • RefreshCategoryAliases loads every section and subsection now, not just rows with aliases, because a row with no alias still has to resolve. That's most of them.
  • A row's own title outranks any alias. Otherwise Roll sports with no subsection row back into Sports #199's "Men's Basketball" alias on sports would have sent the basketball chip to /sports instead of its own page. A chip should reach the most specific page listing the article.

Tags are deliberately untouched: no taxonomy rows, so derived slugs are all they have.

2. The card shows the wrong category

The card takes categories[0]. That article is ["Men's Lacrosse", "From the Playbook", "Sports"] — it's in Columns because of From the Playbook, but it announced itself as a sport.

Ordered in the handler rather than taught to the card: the handler is the only place that knows which section was asked for, so doing it there fixes every surface at once — homepage blocks, section pages, subsection pages, filtered listings — with no component changes.

The two fixes are coupled, which is why they're one PR: matching a category against the section's slugs only works once the category carries the slug the section knows it by. Fix 1 is what makes fix 2 possible.

Rules:

  • A subsection stands on its own — on a subsection page the subsection is the reason the article is there, not the parent it also carries.
  • No section context, no reordering — author pages and unfiltered feeds keep the article's own order, since no category is more relevant there. Single articles untouched for the same reason.
  • Stable partition — two categories both in the section keep the article's order between them, so the kicker doesn't move for unrelated reasons.

Testing

go build, go vet, full suite green. The database integration tests were run against a real MariaDB 11.7 rather than left to skip on a missing CMS_TEST_DSN, including the new alias-vs-own-page precedence case.

One thing the unit tests can't cover: a possessive category only resolves to its slug through the taxonomy cache, which lives in the database package and can't be loaded from a handlers test. The ordering tests use Field Hockey instead, and the comment says why.

🤖 Generated with Claude Code

ssavutu and others added 2 commits August 6, 2026 23:26
The category chip on an article card is a link, and its target was derived
from the category NAME alone. That silently produced URLs no page answers:
"Men's Basketball" canonicalizes to "men-s-basketball" while the
subsection lives at "mens-basketball", so the chip 404s.

    /mens-basketball    200   the real page
    /men-s-basketball   404   what the chip linked to

Both basketballs and both soccers -- the four apostrophe subsections --
have been like this the whole time. It is the same apostrophe
possessiveVariant already absorbs on the matching side; the link never got
the same treatment. Nobody reported it because a chip is a small target
and the article underneath it works.

Resolve through site_taxonomy instead, falling back to the derived slug so
the value is never empty. A category that only reaches a section by alias
now links to that section rather than to nothing, which is what makes the
chip on a men's lacrosse article useful.

RefreshCategoryAliases now loads every section and subsection rather than
only the rows carrying aliases, because a row with no alias still has to
resolve -- that is most of them.

A row's own title outranks any alias: an alias is how a section absorbs
somebody else's category, so it must never take the link away from that
category's own page. The chip should reach the most specific page that
lists the article. Covered by an integration test, run against MariaDB
11.7 rather than left to skip.

Tags are deliberately untouched: they have no taxonomy rows and their
derived slugs are all they have.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An editor reported the Columns block labelling a column "MEN'S LACROSSE".
The card shows one category as its kicker and takes the first one; that
article is ["Men's Lacrosse", "From the Playbook", "Sports"], it is in
Columns because of From the Playbook, and it announced itself as a sport.

Order the categories where the section is already known, rather than
teaching the card to guess. The handler is the only place that knows which
section was asked for, and doing it there fixes every surface at once --
homepage blocks, section pages, subsection pages, filtered listings --
without changing a single component.

This is why the chip slugs had to be resolved through the taxonomy first:
matching a category against the section's slugs only works if the category
carries the slug the section knows it by. "Men's Lacrosse" reaches Sports
by alias, so on a Sports page it leads; in Columns, From the Playbook does.

A subsection stands on its own. On a subsection page the subsection is the
reason the article is there, not the parent section it also carries.

Listings with no section -- an author page, an unfiltered feed -- pass
nothing and keep the article's own order, because no category is more
relevant than another there. Single articles are untouched for the same
reason. The sort is a stable partition, so two categories that are both in
the section keep the article's order between them and the kicker does not
move for unrelated reasons.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ssavutu ssavutu changed the title Point category chips at a page that exists Fix category chips: dead links, and the wrong category on the card Aug 7, 2026
@ssavutu
ssavutu merged commit ac270e8 into main Aug 7, 2026
6 checks passed
@ssavutu
ssavutu deleted the fix/category-chip-slug branch August 7, 2026 03:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant