Composables
Schema.org JSON-LD & Site Meta
Schema composables — emit Article, Review, Product, ItemList, BreadcrumbList JSON-LD for Google rich results, plus a useSiteMeta helper that consolidates title/description/OG/Twitter Card boilerplate.
Schema.org JSON-LD & Site Meta
The useSchema composable is the SEO foundation for every page in the layer. Each export auto-injects a <script type="application/ld+json"> block into the page head — no manual template wiring needed. useSiteMeta consolidates the useSeoMeta + useHead boilerplate (title, description, OG, Twitter Card, canonical, robots) into a single call.
Available composables
| Composable | Emits | Drives |
|---|---|---|
useArticleSchema(input) | BlogPosting with author + publisher + dates | Article rich results |
useReviewSchema(input) | Review with Rating block | Per-review SERP snippets |
useProductSchema(input) | Product + AggregateRating + Offer | Star SERPs (when paired with rating data) |
useBreadcrumbSchema(input) | BreadcrumbList | Breadcrumb SERPs |
useItemListSchema(input) | ItemList (top 50 items) | Carousel / sitelinks SERPs |
useSiteMeta(input) | <title>, <meta>, OG, Twitter Card, canonical, robots | Standard meta tags |
All composables read site identity from appConfig.xRestaurants.name and appConfig.xSchema.siteUrl automatically.
Recommended pattern per page
<script setup>
const route = useRoute()
// 1) Page meta (title, description, OG, Twitter, canonical)
useSiteMeta({
title: 'Best Italian Restaurants in Brooklyn',
description: 'Hand-picked Italian restaurants in Brooklyn — ratings, reviews, and hours.',
path: '/cuisines/italian',
})
// 2) Schema.org — drives Google rich results
useItemListSchema({
name: 'Best Italian Restaurants in Brooklyn',
description: 'Hand-picked Italian restaurants in Brooklyn.',
url: 'https://example.com/cuisines/italian',
items: restaurants.map(r => ({
name: r.name,
url: `https://example.com/restaurants/${r.slug}`,
})),
})
// 3) Breadcrumbs
useBreadcrumbSchema({
items: [
{ label: 'Home', href: '/' },
{ label: 'Cuisines', href: '/cuisines' },
{ label: 'Italian' },
],
})
</script>
Article page pattern
<script setup>
// Articles / features — full BlogPosting with author + publisher
useArticleSchema({
headline: article.title,
description: article.description,
image: article.meta.image,
datePublished: article.meta.date,
author: { name: article.meta.author },
})
useSiteMeta({
title: article.title,
description: article.description,
path: route.path,
type: 'article',
publishedTime: article.meta.date,
author: article.meta.author,
image: article.meta.image,
})
</script>
useSiteMeta() API
| Field | Type | Default | Description |
|---|---|---|---|
title | string | site name | Page title. |
description | string | site tagline | Meta description. |
image | string | xSchema.siteLogo | OG / Twitter image. |
path | string | current route | Used to build canonical URL. |
type | 'website' | 'article' | 'product' | 'website' | OG type. |
publishedTime | string | — | article:published_time (article only). |
modifiedTime | string | — | article:modified_time (article only). |
author | string | — | article:author (article only). |
section | string | — | article:section (article only). |
tags | string[] | — | article:tag (one per tag). |
noindex | boolean | false | Set robots to noindex, nofollow. |
useArticleSchema() API
| Field | Type | Required | Description |
|---|---|---|---|
headline | string | ✅ | Article title. |
description | string | Article description / meta description. | |
image | string | string[] | Hero image. | |
datePublished | string | ✅ | ISO 8601 publish date. |
dateModified | string | ISO 8601 modified date. | |
url | string | Defaults to ${siteUrl}${route.path}. | |
author | { name, url? } | Article author. | |
publisherName | string | Defaults to xRestaurants.name. | |
publisherLogo | string | Publisher logo URL. |
useProductSchema() API
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✅ | Product / restaurant name. |
description | string | Product description. | |
image | string | string[] | Image URL or array. | |
url | string | Canonical URL. | |
brand | string | Brand name (e.g. cuisine type). | |
aggregateRating.ratingValue | number | Average rating (clamped to [0, bestRating]). | |
aggregateRating.ratingCount | number | Required by Google for star SERPs. | |
aggregateRating.reviewCount | number | Separate review count. | |
aggregateRating.bestRating | number | 5 | Best possible rating. |
offer.price | number | Offer price. | |
offer.priceCurrency | string | 'USD' | ISO 4217 currency code. |
offer.availability | string | 'InStock' | InStock / OutOfStock / PreOrder / Discontinued. |
useItemListSchema() API
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✅ | List name (page title). |
description | string | List description. | |
url | string | Canonical URL of the page. | |
items | { name, url }[] | ✅ | List items (capped at 50 for SERPs). |
useBreadcrumbSchema() API
| Field | Type | Required | Description |
|---|---|---|---|
items | { label, href? }[] | ✅ | Breadcrumb trail. Last item (current page) should omit href. |
cleanSchema()
Strips undefined / null / empty-array values from a schema object. Useful when building custom schema shapes:
const schema = cleanSchema({
'@context': 'https://schema.org',
'@type': 'Thing',
name: 'X',
description: undefined, // removed
image: [], // removed
url: 'https://...',
})
AI Context
composable: useSchema
package: "@xenterprises/nuxt-x-restaurants"
use-when: >
Building any page that needs Google rich-result eligibility or standardized
meta tags. useArticleSchema() drives article rich results. useProductSchema()
is the highest-ROI call — drives star SERPs when paired with aggregate
rating data. useBreadcrumbSchema() drives breadcrumb SERPs on every page
with a meaningful navigation trail. useItemListSchema() is essential on
cuisine/neighborhood index pages for carousel/sitelinks SERPs.
useSiteMeta() consolidates the title/description/OG/Twitter Card/canonical
boilerplate into a single call. Every composable auto-injects a
<script type="application/ld+json"> block — no template wiring required.
Always call useSiteMeta() + the relevant schema composables at the top of
each page's <script setup>.
