0% прочитано

Laravel BreadcrumbList JSON-LD у реальному блозі

У ICanUp visible breadcrumbs і BreadcrumbList JSON-LD описують одну й ту саму hierarchy сторінки. Показую, як я пов’язую навігацію зі structured data, формую sequential positions, використовую localized canonical URLs і не додаю окрему SEO hierarchy поверх application breadcrumbs.

10 вересня 2026 р. 8 хв читанняЛаравель

Коли в ICanUp з'явилися breadcrumbs, я могла б окремо побудувати ще одну hierarchy спеціально для JSON-LD.

Але тоді visible navigation і structured data могли б з часом почати описувати різні шляхи.

Тому для мене BreadcrumbList - це структуроване представлення тієї самої ієрархії навігації, яку вже бачить користувач.

Моє головне правило: visible breadcrumbs і BreadcrumbList не повинні мати окремі джерела правди. SEO-схема серіалізує реальну публічну ієрархію навігації.
Laravel visible breadcrumbs converted into BreadcrumbList JSON-LD with localized canonical URLs
Visible breadcrumbs проходять через той самий public URL контракт і перетворюються на BreadcrumbList structured data без окремої SEO-ієрархії.

BreadcrumbList не просто повторює текст breadcrumb labels.

Він описує впорядкований шлях сторінки в середині ієрархії сайту через список ListItem.

Кожен item має position, name і, якщо елемент navigable, public URL.

JSON - Basic BreadcrumbList
{  "@context": "https://schema.org",  "@type": "BreadcrumbList",  "itemListElement": [    {      "@type": "ListItem",      "position": 1,      "name": "Blog",      "item": "https://icanup.com.ua/"    },    {      "@type": "ListItem",      "position": 2,      "name": "Laravel",      "item": "https://icanup.com.ua/categories/laravel"    },    {      "@type": "ListItem",      "position": 3,      "name": "Current post"    }  ]}

Видима ієрархія для мене первинна

Breadcrumbs спочатку мають сенс для людини.

Вони показують, де поточна сторінка знаходиться відносно Blog, Category або інших parent pages.

JSON-LD не повинен вигадувати parent, якого немає у видимій навігації.

Тип сторінки

Видимий шлях

Category

Blog > Laravel

Post

Blog > Laravel > Current post

Static page

Blog > About

Post отримує category у ієрархії

Для технічної post категорія є важливою частиною контексту.

Тому breadcrumb для Post може показувати не тільки Blog і title, а й category між ними.

У результаті ICanUp отримує ієрархію, яка одночасно корисна для навігації і структурованих даних.

Post breadcrumb hierarchy
Blog  |  +-- Laravel        |        +-- Laravel BreadcrumbList JSON-LD у реальному блозі

Позиція генерується з position, а не з ID бази даних

У Schema.org кожен ListItem отримує sequential position.

Це position у breadcrumb path, а не primary key category, menu item або іншої database entity.

Перший item має position 1, другий - 2, третій - 3 незалежно від їхніх database IDs.

PHP - Sequential breadcrumb positions
$items = []; foreach ($breadcrumbs as $index => $breadcrumb) {    $items[] = [        '@type' => 'ListItem',        'position' => $index + 1,        'name' => $breadcrumb['label'],    ];}

Поточна сторінка не обов'язково має URL елемента

У visible breadcrumbs поточна сторінка зазвичай показана останньою і не є clickable.

Я не хочу створювати fake navigation behavior тільки заради schema.

Тому для ненавігаційного елемента name і position можуть залишитися, а item не додається.

JSON - Current non-navigable breadcrumb item
{  "@type": "ListItem",  "position": 3,  "name": "Current post"}
Я не додаю URL елемента механічно до кожного ListItem. Схема навігації має зберегти навігаційну семантику видимої навігації.

Localized URLs мають бути такими самими, як canonical routes

Multilingual blog додає ще одну умову: breadcrumb URL залежить від locale.

У default UK locale public URL не має locale prefix, а EN використовує /en.

BreadcrumbList не повинен мати власну логіку для локалізації URL.

Localized breadcrumb URLs
UK:https://icanup.com.ua/categories/laravel EN:https://icanup.com.ua/en/categories/laravel

Це той самий URL контракт, який я використовую для canonical і hreflang у multilingual Laravel.

Structured data не повинні окремо вирішувати, коли додавати locale prefix.

Генерація маршруту залишається джерелом істини

Я вже проходила через проблему дублювання localized routing logic.

Тому навігаційний URL, канонічний, hreflang та інші споживачі SEO мають спиратися на маршрутизацію додатків, а не вручну об’єднані рядки.

Один route контракт зменшує ризик, що visible link і JSON-LD item почнуть відрізнятися.

Сам підхід до logical route names я окремо описувала у статті про localized URLs і logical routing у Laravel.

Вкладені категорії роблять BreadcrumbList цікавішим

Якщо category tree стає глибшим, breadcrumb path теж може стати довшим.

Наприклад, замість одного Laravel level може з'явитися parent category і child category.

У такій ситуації structured data повинні повторити реальний упорядкований ланцюг предків, а не тільки поточну category.

Nested category breadcrumb
Blog  |  +-- Development        |        +-- Laravel              |              +-- Current post

Labels теж мають бути localized

URL - не єдина localized частина breadcrumbs.

Visible label category або page title також має відповідати поточній locale.

Інакше EN page може отримати правильний EN URL, але UK breadcrumb name всередині JSON-LD.

Part

UK page

EN page

Category label

Laravel

Laravel

Post title

UK localized title

EN localized title

Category URL

/categories/laravel

/en/categories/laravel

BreadcrumbList і BlogPosting можуть жити на одній сторінці

Post page не обмежена одним JSON-LD type.

BlogPosting описує Post entity, тоді як BreadcrumbList описує її місце в ієрархії сайту.

Ці schemas доповнюють одна одну, а не конкурують за роль головного structured object.

JSON - Different structured data responsibilities
[  {    "@type": "BlogPosting",    "headline": "Localized post title"  },  {    "@type": "BreadcrumbList",    "itemListElement": []  }]

Я не дублюю ієрархію навігації на рівні SEO

Найризикованішим рішенням було б окремо зібрати visible breadcrumbs у frontend і вдруге вручну описати ієрархію в SEO service.

Тоді зміна category tree або page structure вимагала б синхронного оновлення двох реалізацій.

Structured data краще будувати з уже нормалізованої breadcrumb collection.

Що я вважаю breadcrumb item контрактом

Field

Навіщо потрібне

label

Visible і schema name

url

Public localized URL для navigable item

navigable

Чи має element item URL

order

Позиція в середині ієрархії

Static pages мають простіший path

Не кожна сторінка потребує ієрархії категорій.

Для static page breadcrumb може бути коротким: Blog і поточна page.

Це ще одна причина не hardcode Post-specific hierarchy всередині BreadcrumbList builder.

Static page breadcrumb
Blog > About

JSON-LD має бути в initial HTML

BreadcrumbList є SEO structured data, тому я перевіряю його не тільки після browser hydration.

Schema повинна бути присутня в page source, який отримує сканер.

Це той самий SSR принцип, який у мене вже з'явився після кейсу, коли meta tags були в browser, але не в initial HTML.

Як я перевіряю BreadcrumbList

BASH - Check BreadcrumbList in raw HTML
curl -s \  https://icanup.com.ua/en/posts/example-slug \  | grep -A 40 '"BreadcrumbList"'

Після raw HTML я також дивлюся сам JSON-LD payload.

Мене цікавить не тільки валідність синтаксису, а й те, чи схема збігається з реальною видимою ієрархією breadcrumb.

Що я перевіряю тестами

  • BreadcrumbList JSON-LD присутній у page source.

  • Visible breadcrumbs і структурована ієрархія мають однаковий порядок.

  • Positions починаються з 1 і йдуть послідовно.

  • Navigable items мають localized public URL.

  • Current non-clickable page не отримує fake item URL.

  • Post ієрархія містить правильну category.

  • Вкладені предки категорії зберігають правильний порядок.

  • UK і EN використовують відповідні localized labels та URLs.

  • Static pages не отримують Post-specific ієрархію.

Що я б не робила

  • Не створювала б окремий breadcrumb tree тільки для SEO.

  • Не використовувала б database ID як ListItem position.

  • Не харколила locale prefixes у JSON-LD builder.

  • Не додавала б item URL до non-navigable current page механічно.

  • Не використовувала б UK labels усередині EN schema.

  • Не пропускала б parent categories, які реально присутні у visible hierarchy.

  • Не покладалася лише на клієнтську вставку JSON-LD.

Для мене BreadcrumbList хороший тоді, коли він не придумує ієрархію для пошукової системи, а точно описує навігацію, яка програма вже показує користувачу.

Що я залишила собі на майбутнє

  • Будувати structured breadcrumbs із тієї самої normalized collection, що і visible UI.
  • Генерувати position із ordered path.
  • Використовувати application routing для item URLs.
  • Локалізувати і URL, і breadcrumb labels.
  • Не додавати item property там, де breadcrumb не navigable.
  • Підтримувати category ancestors як реальний hierarchy chain.
  • Перевіряти BreadcrumbList у initial server-rendered HTML.

Висновок

У ICanUp BreadcrumbList для мене не є окремою SEO navigation system.

Visible breadcrumbs уже знають ієрархію, localized labels і public links. Structured data лише переводять цей contract у Schema.org BreadcrumbList.

Positions будуються з ordered path, navigable items використовують localized URLs, а поточна non-clickable page не отримує фейкову семантику навігації.

У результаті користувач і search engine бачать одну й ту саму site hierarchy, просто в різних representations.