Deploy
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
interface Profile {
|
||||
businessName: string | null
|
||||
schemaType: string
|
||||
phone: string | null
|
||||
email: string | null
|
||||
socials?: { network: string; url: string }[]
|
||||
address: {
|
||||
street: string | null
|
||||
locality: string | null
|
||||
region: string | null
|
||||
postalCode: string | null
|
||||
country: string | null
|
||||
} | null
|
||||
}
|
||||
|
||||
/**
|
||||
* schema.org LocalBusiness data for this business, rendered into the page.
|
||||
*
|
||||
* Server-side, and revalidated hourly rather than per request: this is the
|
||||
* same answer for every visitor, and a crawler should not be waiting on our
|
||||
* backend to see a page.
|
||||
*/
|
||||
export default async function BusinessSchema() {
|
||||
const base = process.env.NEXT_PUBLIC_VULA_COMMERCE_URL
|
||||
const id = process.env.NEXT_PUBLIC_VULA_PROJECT_ID
|
||||
if (!base || !id) return null
|
||||
|
||||
let p: Profile | null = null
|
||||
try {
|
||||
const res = await fetch(base + '/api/public/profile/' + id, { next: { revalidate: 3600 } })
|
||||
if (res.ok) p = (await res.json())?.profile ?? null
|
||||
} catch {
|
||||
// A page without structured data still renders. A page that fails to
|
||||
// render because our backend is slow does not.
|
||||
return null
|
||||
}
|
||||
if (!p?.businessName) return null
|
||||
|
||||
const data: Record<string, unknown> = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': p.schemaType || 'LocalBusiness',
|
||||
name: p.businessName,
|
||||
}
|
||||
if (p.phone) data.telephone = p.phone
|
||||
if (p.email) data.email = p.email
|
||||
// sameAs is how Google ties this site to her Facebook and Instagram pages —
|
||||
// the same entity match that decides whether she appears in the map listing.
|
||||
if (p.socials?.length) data.sameAs = p.socials.map((s) => s.url)
|
||||
if (p.address) {
|
||||
data.address = {
|
||||
'@type': 'PostalAddress',
|
||||
streetAddress: p.address.street,
|
||||
addressLocality: p.address.locality,
|
||||
...(p.address.region ? { addressRegion: p.address.region } : {}),
|
||||
...(p.address.postalCode ? { postalCode: p.address.postalCode } : {}),
|
||||
addressCountry: p.address.country || 'ZA',
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<script
|
||||
type="application/ld+json"
|
||||
// The value is JSON we built ourselves from her own fields, never markup.
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(data).replace(/</g, '\\u003c') }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user