A content page needs a name. It turns out it needs five places to put one, and they are not all allowed to say the same thing. The day that became obvious was the day a footer column came out three times the width of the column next to it.
Here are the five, on one page of pub-trivia.app. Load the FAQ and read them off:
| Where | What it says | | --- | --- | | | Frequently Asked Questions \| PubTrivia | | og:title | Frequently Asked Questions \| PubTrivia | | | Frequently asked questions | | breadcrumb and footer link | FAQ |
Three distinct strings across four slots, and a fifth slot exists for pages inside a cluster, which I will come to.
None of that is sloppiness. Each one has a different job: The is what a search result shows and, more to the point, it should contain the phrase people actually type. "Frequently Asked Questions" is that phrase. "FAQ" is shorter and worse. The og:title has to carry the site name even when the template would have added it, because Next does not apply title.template to openGraph.title. A link preview that says only "Pricing" is a link preview nobody can place. The is read by somebody who has already arrived, so it is allowed to be longer, or in this case simply sentence case, because a heading in title case reads like a form field. The link label has to fit in a footer column next to five other labels.
"Only the handful of pages with that problem" turned out to be optimistic. Of the 69 content nodes, 64 carry an explicit shortLabel. Five do not, and they are exactly the five whose titles were already short: the homepage, /pricing, /about, /features and /solutions.
| title | shortLabel | | --- | --- | | Frequently Asked Questions | FAQ | | Free Quiz Questions and Answers | Questions | | Compare Pub Quiz Software | Compare | | Best Pub Quiz Apps and Software | Best quiz apps | | Free Quiz Night Tools | Tools | | Team and Individual Scoring | Team scoring |
Every one of those long forms is a phrase somebody searches and a disaster in a nav bar. The optional field with a fallback is the right shape for that: it is not two parallel lists that can drift, it is one list with an override on the rows that need it.
So a hub page can be named twice over: once by its own node, and once by the cluster whose front door it is. The header and the footer link it by the cluster's label. The breadcrumb trail links it by labelFor().
For five of the six clusters those two agree, because the hub's short label was written to match. For the solutions hub they do not, and that page is the one where four of the five slots hold different strings:
| Where | What it says | | --- | --- | | | Solutions by Venue \| PubTrivia | | og:title | Solutions by Venue \| PubTrivia | | | Quiz nights, by the kind of place you run | | breadcrumb | Solutions by Venue | | header and footer link | Solutions |
Open the page and you can see the last two in the same viewport: the footer heading says "Solutions", the breadcrumb at the top of the page says "Solutions by Venue". Both are links to pages in the same cluster, generated by the same registry, disagreeing about what the cluster is called.
The cause is the fallback. /solutions has no shortLabel, because its title is only eighteen characters and nothing about it is too long for a column. So labelFor() returns the title, and the title is the one written for a search result, while the nav uses the cluster label written for a nav bar. The field was given a sensible default and the default is wrong in the one case where a second name for the same page already existed.
The fix is one line, shortLabel: 'Solutions', and the more useful observation is about the shape of the bug: an optional field with a fallback cannot be forgotten, it can only be forgotten quietly. Nothing throws. Nothing fails a test. You get a reasonable-looking string in the wrong register, in a place you were not looking, on 1 page out of 69.
The tools hub shows this from the other side. The visible cards say "Team name generator", "Scoresheet generator", "QR code generator", "Round planner". The ItemList in its structured data says:
The markup uses node.title, not labelFor(node). A ListItem is a reference to a page rather than a rendering of a link, so the name it carries should be the page's name, which is the thing in the of the page it points at. The visible card is a link in a grid of four and gets the short form.
It is defensible and I still find it slightly uncomfortable, because the rule everywhere else on this site is that structured data only states what is on the page, and the name in that ListItem is not the text a human sees. The defence is that the url is unambiguous and the title it quotes is the title the destination actually has. If you want to check: open the markup with view-source on the hub, then follow any of those four URLs and read its . They match.
While you have the tools hub open, those four are genuinely useful if you ever run a quiz: the round planner does the arithmetic on how long a night will actually take, and the scoresheet and QR code pages produce printable PDFs in the browser, with no account and nothing uploaded.
