import type { BlogPost, AuthorProfile, PillarMeta, Testimonial, AggregateRating } from "./types"; const SITE_URL = "https://www.qrmaster.net"; export function websiteSchema() { return { '@context': 'https://schema.org', '@type': 'WebSite', '@id': `${SITE_URL}/#website`, name: 'QR Master', url: SITE_URL, inLanguage: 'en', mainEntityOfPage: SITE_URL, publisher: { '@id': `${SITE_URL}/#organization`, }, potentialAction: { '@type': 'SearchAction', target: { '@type': 'EntryPoint', urlTemplate: `${SITE_URL}/blog?q={search_term_string}`, }, 'query-input': 'required name=search_term_string', }, }; } export function organizationSchema() { return { '@context': 'https://schema.org', '@type': 'Organization', '@id': `${SITE_URL}/#organization`, name: 'QR Master', alternateName: 'QRMaster', url: SITE_URL, logo: { '@type': 'ImageObject', url: `${SITE_URL}/static/og-image.png`, width: 1200, height: 630, }, sameAs: [ 'https://www.wikidata.org/wiki/Q137918857', 'https://x.com/TIMO_QRMASTER', 'https://www.linkedin.com/in/qr-master-44b6863a2/', 'https://www.instagram.com/qrmaster_net/', 'https://www.pr.com/press-release/959199', ], contactPoint: [{ '@type': 'ContactPoint', contactType: 'Customer Support', email: 'support@qrmaster.net', availableLanguage: ['en', 'de'], }], }; } export function blogPostingSchema(post: BlogPost, author?: AuthorProfile) { const url = `${SITE_URL}/blog/${post.slug}`; // Use post.authorName if available (from AEO/GEO optimization), otherwise fall back to author profile const authorSchema = post.authorName ? { "@type": "Person", name: post.authorName, jobTitle: post.authorTitle, url: `${SITE_URL}/#organization`, } : author ? { "@type": "Person", name: author.name, url: `${SITE_URL}/authors/${author.slug}`, sameAs: author.sameAs ?? undefined, knowsAbout: author.knowsAbout ?? undefined } : { "@type": "Organization", name: "QR Master" }; return { "@context": "https://schema.org", "@type": "BlogPosting", headline: post.title, description: post.description, url, datePublished: post.datePublished, dateModified: post.dateModified || post.datePublished, image: post.heroImage ? `${SITE_URL}${post.heroImage}` : undefined, author: authorSchema, publisher: { "@type": "Organization", name: "QR Master", url: SITE_URL, logo: { '@type': 'ImageObject', url: `${SITE_URL}/static/og-image.png`, } }, isPartOf: { '@type': 'Blog', '@id': `${SITE_URL}/blog#blog`, name: 'QR Master Blog', url: `${SITE_URL}/blog`, }, }; } export function howToSchema(post: BlogPost, author?: AuthorProfile) { const url = `${SITE_URL}/blog/${post.slug}`; const steps = (post.keySteps ?? []).map((text, idx) => ({ "@type": "HowToStep", position: idx + 1, name: `Step ${idx + 1}`, text })); // Use post.authorName if available, otherwise fall back to author profile const authorSchema = post.authorName ? { "@type": "Person", name: post.authorName, jobTitle: post.authorTitle } : author ? { "@type": "Person", name: author.name, url: `${SITE_URL}/authors/${author.slug}` } : undefined; return { "@context": "https://schema.org", "@type": "HowTo", name: post.title, description: post.description, url: `${url}#howto`, step: steps, author: authorSchema }; } export function pillarPageSchema(meta: PillarMeta, posts: BlogPost[]) { const url = `${SITE_URL}/learn/${meta.key}`; return { "@context": "https://schema.org", "@type": "WebPage", name: meta.title, description: meta.description, url, mainEntity: { "@type": "ItemList", itemListElement: posts.map((p, i) => ({ "@type": "ListItem", position: i + 1, url: `${SITE_URL}/blog/${p.slug}`, name: p.title })) } }; } export function faqPageSchema(faqs: { question: string, answer: string }[]) { return { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faqs.map((faq) => ({ '@type': 'Question', name: faq.question, acceptedAnswer: { '@type': 'Answer', text: faq.answer, }, })), }; } export function breadcrumbSchema(items: { name: string; url: string }[]) { return { '@context': 'https://schema.org', '@type': 'BreadcrumbList', itemListElement: items.map((item, index) => ({ '@type': 'ListItem', position: index + 1, name: item.name, item: item.url.startsWith('http') ? item.url : `https://www.qrmaster.net${item.url}`, })), }; } export function softwareApplicationSchema(aggregateRating?: AggregateRating) { const schema: any = { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: 'QR Master', applicationCategory: 'BusinessApplication', operatingSystem: 'Web Browser', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR', availability: 'https://schema.org/InStock', priceValidUntil: '2026-12-31' }, publisher: { '@id': `${SITE_URL}/#organization`, } }; if (aggregateRating) { schema.aggregateRating = { '@type': 'AggregateRating', ratingValue: aggregateRating.ratingValue, reviewCount: aggregateRating.reviewCount, bestRating: aggregateRating.bestRating, worstRating: aggregateRating.worstRating }; } return schema; } export function authorPageSchema(author: AuthorProfile, posts?: BlogPost[]) { const url = `${SITE_URL}/authors/${author.slug}`; return { '@context': 'https://schema.org', '@type': 'ProfilePage', mainEntity: { '@type': 'Person', '@id': url, name: author.name, jobTitle: author.role, description: author.bio, image: author.image ? `${SITE_URL}${author.image}` : undefined, sameAs: author.sameAs?.length ? author.sameAs : undefined, knowsAbout: author.knowsAbout?.length ? author.knowsAbout : undefined, url, }, about: posts?.length ? { '@type': 'ItemList', itemListElement: posts.map((p, i) => ({ '@type': 'ListItem', position: i + 1, url: `${SITE_URL}/blog/${p.slug}`, name: p.title, })), } : undefined, }; } export function articleSchema(params: { headline: string; description: string; image?: string; datePublished: string; dateModified?: string; author: string; url?: string; }) { return { '@context': 'https://schema.org', '@type': 'Article', headline: params.headline, description: params.description, image: params.image, datePublished: params.datePublished, dateModified: params.dateModified || params.datePublished, author: { '@type': 'Organization', name: params.author, }, publisher: { '@type': 'Organization', name: 'QR Master', url: SITE_URL, logo: { '@type': 'ImageObject', url: `${SITE_URL}/static/og-image.png`, }, }, url: params.url, }; } export function reviewSchema(testimonial: Testimonial) { return { '@context': 'https://schema.org', '@type': 'Review', itemReviewed: { '@type': 'SoftwareApplication', name: 'QR Master', description: 'Professional QR code generator with dynamic QR codes, analytics, and customization.', image: `${SITE_URL}/static/og-image.png`, applicationCategory: 'BusinessApplication', operatingSystem: 'Web Browser', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR', availability: 'https://schema.org/InStock', priceValidUntil: '2026-12-31' } }, reviewRating: { '@type': 'Rating', ratingValue: testimonial.rating, bestRating: 5, worstRating: 1 }, author: { '@type': 'Person', name: testimonial.author.name }, datePublished: testimonial.datePublished, reviewBody: testimonial.content, headline: testimonial.title }; } export function aggregateRatingSchema(aggregateRating: AggregateRating) { return { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: 'QR Master', description: 'Professional QR code generator with dynamic QR codes, analytics, and customization.', image: `${SITE_URL}/static/og-image.png`, applicationCategory: 'BusinessApplication', operatingSystem: 'Web Browser', url: SITE_URL, offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR', availability: 'https://schema.org/InStock', priceValidUntil: '2026-12-31' }, aggregateRating: { '@type': 'AggregateRating', ratingValue: aggregateRating.ratingValue, reviewCount: aggregateRating.reviewCount, bestRating: aggregateRating.bestRating, worstRating: aggregateRating.worstRating } }; } export interface NewsArticleParams { headline: string; datePublished: string; description: string; url?: string; } export function newsArticleSchema(params: NewsArticleParams) { return { '@context': 'https://schema.org', '@type': 'NewsArticle', headline: params.headline, datePublished: params.datePublished, description: params.description, url: params.url || SITE_URL, author: { '@type': 'Organization', name: 'QR Master', '@id': `${SITE_URL}/#organization`, }, publisher: { '@type': 'Organization', name: 'QR Master', '@id': `${SITE_URL}/#organization`, logo: { '@type': 'ImageObject', url: `${SITE_URL}/static/og-image.png`, width: 1200, height: 630, }, }, mainEntityOfPage: { '@type': 'WebPage', '@id': params.url || SITE_URL, }, }; }