refactor: update schema handling and improve SEO metadata
- Changed schema type from WithContext<Thing> to Thing[] in Head, BaseLayout, and JsonLd components for better flexibility. - Added optional robots meta tag to Head component. - Updated JSON-LD generation in JsonLd component to include a structured payload. - Enhanced page and blog schemas to support breadcrumb and person schemas for improved SEO. - Introduced new utility schemas for website and person to streamline schema generation. - Refactored existing schemas to align with the new structure and ensure consistency across components.
This commit is contained in:
@@ -1,15 +1,16 @@
|
|||||||
---
|
---
|
||||||
import type { WithContext, Thing } from "schema-dts";
|
import type { Thing } from "schema-dts";
|
||||||
import JsonLd from "./JsonLd.astro";
|
import JsonLd from "./JsonLd.astro";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
readonly description: string;
|
readonly description: string;
|
||||||
readonly preview: string;
|
readonly preview: string;
|
||||||
readonly schema: WithContext<Thing>;
|
readonly robots?: string;
|
||||||
|
readonly schema: Thing[];
|
||||||
readonly title: string;
|
readonly title: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const { description, preview, schema, title } = Astro.props;
|
const { description, preview, robots = "index, follow", schema, title } = Astro.props;
|
||||||
|
|
||||||
const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
|
const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
|
||||||
const previewUrl = new URL(preview, Astro.site);
|
const previewUrl = new URL(preview, Astro.site);
|
||||||
@@ -21,7 +22,7 @@ const previewUrl = new URL(preview, Astro.site);
|
|||||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||||
|
|
||||||
<meta name="description" content={description} />
|
<meta name="description" content={description} />
|
||||||
<meta name="robots" content="index, follow" />
|
<meta name="robots" content={robots} />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
<link href="/feed.xml" rel="alternate" title="RSS" type="application/atom+xml" />
|
<link href="/feed.xml" rel="alternate" title="RSS" type="application/atom+xml" />
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
---
|
---
|
||||||
import type { WithContext, Thing } from "schema-dts";
|
import type { Thing } from "schema-dts";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
readonly schema: WithContext<Thing>;
|
readonly schema: Thing[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const { schema } = Astro.props;
|
const { schema } = Astro.props;
|
||||||
const json = JSON.stringify(schema);
|
|
||||||
|
const payload = {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@graph": schema,
|
||||||
|
};
|
||||||
|
|
||||||
|
const json = JSON.stringify(payload);
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- JSON-LD -->
|
<!-- JSON-LD -->
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
import type { WithContext, Thing } from "schema-dts";
|
import type { Thing } from "schema-dts";
|
||||||
import Analytics from "../components/Analytics.astro";
|
import Analytics from "../components/Analytics.astro";
|
||||||
import Head from "../components/Head.astro";
|
import Head from "../components/Head.astro";
|
||||||
import Header from "../components/Header.astro";
|
import Header from "../components/Header.astro";
|
||||||
@@ -9,15 +9,16 @@ type Props = {
|
|||||||
readonly description: string;
|
readonly description: string;
|
||||||
readonly lang: string;
|
readonly lang: string;
|
||||||
readonly preview: string;
|
readonly preview: string;
|
||||||
readonly schema: WithContext<Thing>;
|
readonly robots?: string;
|
||||||
|
readonly schema: Thing[];
|
||||||
readonly title: string;
|
readonly title: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const { description, lang, preview, schema, title } = Astro.props;
|
const { description, lang, preview, robots, schema, title } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang={lang}>
|
<html lang={lang}>
|
||||||
<Head title={title} description={description} preview={preview} schema={schema} />
|
<Head title={title} description={description} preview={preview} robots={robots} schema={schema} />
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<main>
|
<main>
|
||||||
|
|||||||
@@ -8,16 +8,20 @@ const description = "The page you're looking for doesn't exist!";
|
|||||||
const preview = config.og.defaultPreview;
|
const preview = config.og.defaultPreview;
|
||||||
const lang = "en";
|
const lang = "en";
|
||||||
|
|
||||||
const schema = pageSchema({
|
const siteUrl = new URL("/", Astro.site).toString();
|
||||||
siteUrl: new URL("/", Astro.site).toString(),
|
|
||||||
page: "/404",
|
const schema = [
|
||||||
title,
|
pageSchema({
|
||||||
description,
|
siteUrl,
|
||||||
lang,
|
page: "/404",
|
||||||
});
|
title,
|
||||||
|
description,
|
||||||
|
lang,
|
||||||
|
}),
|
||||||
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={title} description={description} preview={preview} lang={lang} schema={schema}>
|
<Layout title={title} description={description} preview={preview} lang={lang} robots="noindex, follow" schema={schema}>
|
||||||
<div style={{ "text-align": "center" }}>
|
<div style={{ "text-align": "center" }}>
|
||||||
<h1>404</h1>
|
<h1>404</h1>
|
||||||
<p><strong>Page not found</strong></p>
|
<p><strong>Page not found</strong></p>
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
---
|
---
|
||||||
import { type CollectionEntry, getCollection, render } from "astro:content";
|
import { type CollectionEntry, getCollection, render } from "astro:content";
|
||||||
import Comments from "../../components/Comments.astro";
|
|
||||||
import Layout from "../../layouts/BaseLayout.astro";
|
|
||||||
import blogPostSchema from "../../utils/schemas/blogPostSchema";
|
import blogPostSchema from "../../utils/schemas/blogPostSchema";
|
||||||
|
import breadcrumbSchema from "../../utils/schemas/breadcrumbSchema";
|
||||||
|
import Comments from "../../components/Comments.astro";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import Layout from "../../layouts/BaseLayout.astro";
|
||||||
|
import personSchema from "../../utils/schemas/personSchema";
|
||||||
|
import websiteSchema from "../../utils/schemas/websiteSchema";
|
||||||
|
import { config } from "../../config";
|
||||||
|
|
||||||
type Props = CollectionEntry<"blog">;
|
type Props = CollectionEntry<"blog">;
|
||||||
|
|
||||||
@@ -33,17 +37,31 @@ const dateModified = post.data.dateModified?.toISOString();
|
|||||||
const datePublished = post.data.datePublished.toISOString();
|
const datePublished = post.data.datePublished.toISOString();
|
||||||
const formattedDate = dayjs(post.data.datePublished.toString()).format("MMMM DD, YYYY");
|
const formattedDate = dayjs(post.data.datePublished.toString()).format("MMMM DD, YYYY");
|
||||||
|
|
||||||
const schema = blogPostSchema({
|
const siteUrl = new URL("/", Astro.site).toString();
|
||||||
siteUrl: new URL("/", Astro.site).toString(),
|
|
||||||
dateModified,
|
const schema = [
|
||||||
datePublished,
|
websiteSchema({ siteUrl, name: config.og.website, description, lang }),
|
||||||
description,
|
personSchema({ siteUrl }),
|
||||||
isBasedOn,
|
blogPostSchema({
|
||||||
lang,
|
siteUrl,
|
||||||
preview,
|
dateModified,
|
||||||
slug,
|
datePublished,
|
||||||
title,
|
description,
|
||||||
});
|
isBasedOn,
|
||||||
|
lang,
|
||||||
|
preview,
|
||||||
|
slug,
|
||||||
|
title,
|
||||||
|
}),
|
||||||
|
breadcrumbSchema({
|
||||||
|
siteUrl,
|
||||||
|
items: [
|
||||||
|
{ name: "Home", url: "/" },
|
||||||
|
{ name: "Blog", url: "/blog/" },
|
||||||
|
{ name: title, url: `/blog/${slug}` },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ import type { CollectionEntry } from "astro:content";
|
|||||||
import { config } from "../../config";
|
import { config } from "../../config";
|
||||||
import { getCollection } from "astro:content";
|
import { getCollection } from "astro:content";
|
||||||
import blogSchema from "../../utils/schemas/blogSchema";
|
import blogSchema from "../../utils/schemas/blogSchema";
|
||||||
|
import breadcrumbSchema from "../../utils/schemas/breadcrumbSchema";
|
||||||
import Layout from "../../layouts/BaseLayout.astro";
|
import Layout from "../../layouts/BaseLayout.astro";
|
||||||
import PostElement from "../../components/PostElement.astro";
|
import PostElement from "../../components/PostElement.astro";
|
||||||
import RSSIcon from "../../components/Icons/RSS.astro";
|
import RSSIcon from "../../components/Icons/RSS.astro";
|
||||||
|
import websiteSchema from "../../utils/schemas/websiteSchema";
|
||||||
|
|
||||||
const posts = await getCollection("blog", ({ data }) => {
|
const posts = await getCollection("blog", ({ data }) => {
|
||||||
return data.draft !== true;
|
return data.draft !== true;
|
||||||
@@ -29,11 +31,19 @@ const description = "Explore Valentin Popov's blog on software development, tech
|
|||||||
const preview = config.og.defaultPreview;
|
const preview = config.og.defaultPreview;
|
||||||
const lang = "en";
|
const lang = "en";
|
||||||
|
|
||||||
const schema = blogSchema({
|
const siteUrl = new URL("/", Astro.site).toString();
|
||||||
siteUrl: new URL("/", Astro.site).toString(),
|
|
||||||
title,
|
const schema = [
|
||||||
posts,
|
websiteSchema({ siteUrl, name: config.og.website, description, lang }),
|
||||||
});
|
blogSchema({ siteUrl, title, description, lang, posts }),
|
||||||
|
breadcrumbSchema({
|
||||||
|
siteUrl,
|
||||||
|
items: [
|
||||||
|
{ name: "Home", url: "/" },
|
||||||
|
{ name: "Blog", url: "/blog/" },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
];
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={title} description={description} preview={preview} lang={lang} schema={schema}>
|
<Layout title={title} description={description} preview={preview} lang={lang} schema={schema}>
|
||||||
|
|||||||
@@ -3,21 +3,19 @@ import { config } from "../config";
|
|||||||
import LatestPostsSection from "../components/Sections/LatestPosts.astro";
|
import LatestPostsSection from "../components/Sections/LatestPosts.astro";
|
||||||
import Layout from "../layouts/BaseLayout.astro";
|
import Layout from "../layouts/BaseLayout.astro";
|
||||||
import pageSchema from "../utils/schemas/pageSchema";
|
import pageSchema from "../utils/schemas/pageSchema";
|
||||||
|
import personSchema from "../utils/schemas/personSchema";
|
||||||
import SocialLinksSection from "../components/Sections/SocialLinks.astro";
|
import SocialLinksSection from "../components/Sections/SocialLinks.astro";
|
||||||
import WelcomeSection from "../components/Sections/Welcome.astro";
|
import WelcomeSection from "../components/Sections/Welcome.astro";
|
||||||
|
import websiteSchema from "../utils/schemas/websiteSchema";
|
||||||
|
|
||||||
const title = "Valentin Popov – Software Developer & Team Lead | Tech Insights";
|
const title = "Valentin Popov – Software Developer & Team Lead | Tech Insights";
|
||||||
const description = "Blog by Valentin Popov — software developer and team lead writing about code, side projects, digital tools, and fun experiments.";
|
const description = "Blog by Valentin Popov — software developer and team lead writing about code, side projects, digital tools, and fun experiments.";
|
||||||
const preview = config.og.defaultPreview;
|
const preview = config.og.defaultPreview;
|
||||||
const lang = "en";
|
const lang = "en";
|
||||||
|
|
||||||
const schema = pageSchema({
|
const siteUrl = new URL("/", Astro.site).toString();
|
||||||
siteUrl: new URL("/", Astro.site).toString(),
|
|
||||||
page: "/",
|
const schema = [websiteSchema({ siteUrl, name: config.og.website, description, lang }), personSchema({ siteUrl }), pageSchema({ siteUrl, page: "/", title, description, lang, type: "ProfilePage" })];
|
||||||
title,
|
|
||||||
description,
|
|
||||||
lang,
|
|
||||||
});
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={title} description={description} preview={preview} lang={lang} schema={schema}>
|
<Layout title={title} description={description} preview={preview} lang={lang} schema={schema}>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { WithContext, BlogPosting } from "schema-dts";
|
import type { BlogPosting } from "schema-dts";
|
||||||
import { config } from "../../config";
|
import { personId, websiteId } from "./ids";
|
||||||
|
|
||||||
export type BlogPostSchemaParams = {
|
export type BlogPostSchemaParams = {
|
||||||
readonly dateModified: string;
|
readonly dateModified: string;
|
||||||
@@ -13,25 +13,26 @@ export type BlogPostSchemaParams = {
|
|||||||
readonly title: string;
|
readonly title: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ({ siteUrl, slug, title, description, preview, datePublished, dateModified, lang, isBasedOn }: BlogPostSchemaParams): WithContext<BlogPosting> => ({
|
export default ({ siteUrl, slug, title, description, preview, datePublished, dateModified, lang, isBasedOn }: BlogPostSchemaParams): BlogPosting => {
|
||||||
"@context": "https://schema.org",
|
const url = new URL(`/blog/${slug}`, siteUrl).toString();
|
||||||
"@type": "BlogPosting",
|
|
||||||
"url": new URL(`/blog/${slug}`, siteUrl).toString(),
|
return {
|
||||||
"headline": title,
|
"@type": "BlogPosting",
|
||||||
"description": description,
|
"@id": url,
|
||||||
"image": new URL(preview, siteUrl).toString(),
|
"url": url,
|
||||||
"datePublished": datePublished,
|
"headline": title,
|
||||||
"dateModified": dateModified,
|
"description": description,
|
||||||
"inLanguage": lang,
|
"image": new URL(preview, siteUrl).toString(),
|
||||||
"author": {
|
"datePublished": datePublished,
|
||||||
"@type": "Person",
|
"dateModified": dateModified,
|
||||||
"name": config.author.name,
|
"inLanguage": lang,
|
||||||
"url": config.author.url,
|
"author": { "@id": personId(siteUrl) },
|
||||||
"sameAs": config.author.sameAs,
|
"publisher": { "@id": personId(siteUrl) },
|
||||||
},
|
"isPartOf": { "@id": websiteId(siteUrl) },
|
||||||
"mainEntityOfPage": {
|
"mainEntityOfPage": {
|
||||||
"@type": "WebPage",
|
"@type": "WebPage",
|
||||||
"@id": new URL(`/blog/${slug}`, siteUrl).toString(),
|
"@id": url,
|
||||||
},
|
},
|
||||||
...(isBasedOn && { isBasedOn: isBasedOn }),
|
...(isBasedOn && { isBasedOn: isBasedOn }),
|
||||||
});
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,26 +1,36 @@
|
|||||||
import type { WithContext, CollectionPage } from "schema-dts";
|
import type { CollectionPage } from "schema-dts";
|
||||||
import type { CollectionEntry } from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
|
import { websiteId } from "./ids";
|
||||||
|
|
||||||
export type BlogSchemaParams = {
|
export type BlogSchemaParams = {
|
||||||
|
readonly description: string;
|
||||||
|
readonly lang: string;
|
||||||
readonly posts: CollectionEntry<"blog">[];
|
readonly posts: CollectionEntry<"blog">[];
|
||||||
readonly siteUrl: string;
|
readonly siteUrl: string;
|
||||||
readonly title: string;
|
readonly title: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ({ siteUrl, title, posts }: BlogSchemaParams): WithContext<CollectionPage> => ({
|
export default ({ siteUrl, title, description, lang, posts }: BlogSchemaParams): CollectionPage => {
|
||||||
"@context": "https://schema.org",
|
const url = new URL("/blog/", siteUrl).toString();
|
||||||
"@type": "CollectionPage",
|
|
||||||
"url": new URL("/blog/", siteUrl).toString(),
|
return {
|
||||||
"name": title,
|
"@type": "CollectionPage",
|
||||||
"mainEntity": {
|
"@id": url,
|
||||||
"@type": "ItemList",
|
"url": url,
|
||||||
"itemListOrder": "https://schema.org/ItemListOrderDescending",
|
"name": title,
|
||||||
"numberOfItems": posts.length,
|
"description": description,
|
||||||
"itemListElement": posts.map((post, index) => ({
|
"inLanguage": lang,
|
||||||
"@type": "ListItem",
|
"isPartOf": { "@id": websiteId(siteUrl) },
|
||||||
"position": index + 1,
|
"mainEntity": {
|
||||||
"url": new URL(`/blog/${post.id}`, siteUrl).toString(),
|
"@type": "ItemList",
|
||||||
"name": post.data.title,
|
"itemListOrder": "https://schema.org/ItemListOrderDescending",
|
||||||
})),
|
"numberOfItems": posts.length,
|
||||||
},
|
"itemListElement": posts.map((post, index) => ({
|
||||||
});
|
"@type": "ListItem",
|
||||||
|
"position": index + 1,
|
||||||
|
"url": new URL(`/blog/${post.id}`, siteUrl).toString(),
|
||||||
|
"name": post.data.title,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
21
src/utils/schemas/breadcrumbSchema.ts
Normal file
21
src/utils/schemas/breadcrumbSchema.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import type { BreadcrumbList } from "schema-dts";
|
||||||
|
|
||||||
|
export type BreadcrumbItem = {
|
||||||
|
readonly name: string;
|
||||||
|
readonly url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BreadcrumbSchemaParams = {
|
||||||
|
readonly items: BreadcrumbItem[];
|
||||||
|
readonly siteUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ({ items, siteUrl }: BreadcrumbSchemaParams): BreadcrumbList => ({
|
||||||
|
"@type": "BreadcrumbList",
|
||||||
|
"itemListElement": items.map((item, index) => ({
|
||||||
|
"@type": "ListItem",
|
||||||
|
"position": index + 1,
|
||||||
|
"name": item.name,
|
||||||
|
"item": new URL(item.url, siteUrl).toString(),
|
||||||
|
})),
|
||||||
|
});
|
||||||
3
src/utils/schemas/ids.ts
Normal file
3
src/utils/schemas/ids.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export const websiteId = (siteUrl: string): string => new URL("#website", siteUrl).toString();
|
||||||
|
|
||||||
|
export const personId = (siteUrl: string): string => new URL("#person", siteUrl).toString();
|
||||||
@@ -1,23 +1,36 @@
|
|||||||
import type { WithContext, WebPage } from "schema-dts";
|
import type { ProfilePage, WebPage } from "schema-dts";
|
||||||
|
import { personId, websiteId } from "./ids";
|
||||||
|
|
||||||
export type WebsiteSchemaParams = {
|
export type WebsiteSchemaParams = {
|
||||||
readonly description: string;
|
readonly description: string;
|
||||||
|
readonly lang: string;
|
||||||
|
readonly mainEntityId?: string;
|
||||||
readonly page: string;
|
readonly page: string;
|
||||||
readonly siteUrl: string;
|
readonly siteUrl: string;
|
||||||
readonly title: string;
|
readonly title: string;
|
||||||
readonly lang: string;
|
readonly type?: "WebPage" | "ProfilePage";
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ({ siteUrl, page, title, description, lang }: WebsiteSchemaParams): WithContext<WebPage> => ({
|
export default ({ siteUrl, page, title, description, lang, type = "WebPage", mainEntityId }: WebsiteSchemaParams): WebPage | ProfilePage => {
|
||||||
"@context": "https://schema.org",
|
const url = new URL(page, siteUrl).toString();
|
||||||
"@type": "WebPage",
|
|
||||||
"@id": new URL(page, siteUrl).toString(),
|
const base = {
|
||||||
"url": new URL(page, siteUrl).toString(),
|
"@type": type,
|
||||||
"name": title,
|
"@id": url,
|
||||||
"description": description,
|
"url": url,
|
||||||
"inLanguage": lang,
|
"name": title,
|
||||||
"mainEntity": {
|
"description": description,
|
||||||
"@type": "WebSite",
|
"inLanguage": lang,
|
||||||
"@id": new URL("/", siteUrl).toString(),
|
"isPartOf": { "@id": websiteId(siteUrl) },
|
||||||
},
|
} as const;
|
||||||
});
|
|
||||||
|
if (type === "ProfilePage") {
|
||||||
|
return {
|
||||||
|
...base,
|
||||||
|
"@type": "ProfilePage",
|
||||||
|
"mainEntity": { "@id": mainEntityId ?? personId(siteUrl) },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return base;
|
||||||
|
};
|
||||||
|
|||||||
17
src/utils/schemas/personSchema.ts
Normal file
17
src/utils/schemas/personSchema.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import type { Person } from "schema-dts";
|
||||||
|
import { config } from "../../config";
|
||||||
|
import { personId } from "./ids";
|
||||||
|
|
||||||
|
export type PersonSchemaParams = {
|
||||||
|
readonly siteUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ({ siteUrl }: PersonSchemaParams): Person => ({
|
||||||
|
"@type": "Person",
|
||||||
|
"@id": personId(siteUrl),
|
||||||
|
"name": config.author.name,
|
||||||
|
"url": config.author.url,
|
||||||
|
"email": config.author.email,
|
||||||
|
"image": new URL(config.og.defaultPreview, siteUrl).toString(),
|
||||||
|
"sameAs": config.author.sameAs,
|
||||||
|
});
|
||||||
23
src/utils/schemas/websiteSchema.ts
Normal file
23
src/utils/schemas/websiteSchema.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import type { WebSite } from "schema-dts";
|
||||||
|
import { config } from "../../config";
|
||||||
|
import { personId, websiteId } from "./ids";
|
||||||
|
|
||||||
|
export type WebsiteSchemaParams = {
|
||||||
|
readonly description: string;
|
||||||
|
readonly lang: string;
|
||||||
|
readonly name: string;
|
||||||
|
readonly siteUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ({ siteUrl, name, description, lang }: WebsiteSchemaParams): WebSite => ({
|
||||||
|
"@type": "WebSite",
|
||||||
|
"@id": websiteId(siteUrl),
|
||||||
|
"url": siteUrl,
|
||||||
|
"name": name,
|
||||||
|
"description": description,
|
||||||
|
"inLanguage": lang,
|
||||||
|
"publisher": { "@id": personId(siteUrl) },
|
||||||
|
"author": { "@id": personId(siteUrl) },
|
||||||
|
"copyrightHolder": { "@id": personId(siteUrl) },
|
||||||
|
"sameAs": config.author.sameAs,
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user