Skip to content

Commit 976a56e

Browse files
Add generated schema based off schema.org blogpost type
1 parent 2b0b414 commit 976a56e

File tree

4 files changed

+77
-6
lines changed

4 files changed

+77
-6
lines changed

src/layouts/BlogPost.astro

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const {
2727
tags,
2828
title,
2929
updatedDate,
30+
schema,
3031
} = Astro.props;
3132
const hasUpdatedDate = updatedDate && updatedDate !== pubDate;
3233
const isNewsletter = tags.includes("newsletter");
@@ -51,6 +52,11 @@ const newsletterSeriesTitle = newsletterSeriesData?.title ?? "";
5152
srcImage={coverImage?.src}
5253
title={title}
5354
/>
55+
{
56+
schema && (
57+
<script type="application/ld+json" set:html={JSON.stringify(schema)} />
58+
)
59+
}
5460
</head>
5561

5662
<BaseBody>

src/layouts/Writing.astro

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Footer from "../components/Footer.astro";
77
import Header from "../components/Header.astro";
88
import TitleHeading from "../components/TitleHeading.astro";
99
import writingImage from "../images/writing.png";
10+
import { generateWritingListSchema } from "../utils/schemas";
1011
1112
type Props = {
1213
title?: string;
@@ -60,6 +61,8 @@ const toPascalCase = (tag: string): string => {
6061
.join(" ");
6162
};
6263
64+
const schema = posts.length > 0 ? generateWritingListSchema(posts) : null;
65+
6366
const { title = "Writing", currentTag } = Astro.props;
6467
---
6568

@@ -72,6 +75,11 @@ const { title = "Writing", currentTag } = Astro.props;
7275
srcImage={writingImage.src}
7376
title={title || SITE_TITLE}
7477
/>
78+
{
79+
schema && (
80+
<script type="application/ld+json" set:html={JSON.stringify(schema)} />
81+
)
82+
}
7583
</head>
7684
<BaseBody>
7785
<Header />
@@ -82,9 +90,7 @@ const { title = "Writing", currentTag } = Astro.props;
8290
<slot />
8391
</div>
8492
<div class="col-span-12 md:block md:col-span-3">
85-
<ul
86-
class="flex flex-wrap gap-2 list-none m-0 p-0 print:hidden mb-4"
87-
>
93+
<ul class="flex flex-wrap gap-2 list-none m-0 p-0 print:hidden mb-4">
8894
{
8995
isActive("/blog") && (
9096
<li class="text-green-700 dark:text-green-300 border-blue-800 dark:border-blue-500 border-solid border-b-2">

src/pages/blog/[...slug].astro

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,28 @@
22
import { getCollection, getEntry } from "astro:content";
33
import BlogPost from "../../layouts/BlogPost.astro";
44
import type { CollectionEntry } from "astro:content";
5+
import { generateWritingPieceSchema } from '../../utils/schemas';
6+
7+
type Props = CollectionEntry<"writing">;
58
69
export async function getStaticPaths() {
710
const posts = await getCollection("writing");
8-
return posts.map((post) => ({
11+
return posts.map((post: Props) => ({
912
params: { slug: post.slug },
1013
props: post,
1114
}));
1215
}
13-
type Props = CollectionEntry<"writing">;
1416
1517
const post = Astro.props;
1618
const { Content } = await post.render();
19+
const schema = post ? generateWritingPieceSchema(post) : null;
1720
1821
const blogPost = await getEntry("writing", post.slug);
1922
const { remarkPluginFrontmatter } = await blogPost.render();
2023
const { minutesRead } = remarkPluginFrontmatter ?? {};
2124
---
2225

23-
<BlogPost {...post.data} minutesRead={minutesRead}>
26+
<BlogPost {...post.data} minutesRead={minutesRead} schema={schema}>
2427
<h1>{post.data.title}</h1>
2528
<Content />
2629
</BlogPost>

src/utils/schemas.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import type { CollectionEntry } from "astro:content";
2+
3+
type WritingPiece = CollectionEntry<"writing">;
4+
5+
export function generateWritingPieceSchema(post: WritingPiece) {
6+
return {
7+
"@context": "https://schema.org",
8+
"@type": "BlogPosting",
9+
headline: post.data.title,
10+
description: post.data.description,
11+
author: {
12+
"@type": "Person",
13+
name: "Jeremy Wong",
14+
url: "https://craftbyzen.com/",
15+
},
16+
datePublished: post.data.pubDate,
17+
dateModified: post.data.updatedDate || post.data.pubDate,
18+
keywords: post.data.tags?.join(", "),
19+
url: `https://craftbyzen.com/blog/${post.slug}`,
20+
image: post.data.heroImage || "",
21+
mainEntityOfPage: {
22+
"@type": "WebPage",
23+
"@id": `https://craftbyzen.com/blog/${post.slug}`,
24+
},
25+
};
26+
}
27+
28+
export function generateWritingListSchema(posts: any[]) {
29+
return {
30+
"@context": "https://schema.org",
31+
"@type": "CollectionPage",
32+
"mainEntity": {
33+
"@type": "ItemList",
34+
"itemListElement": posts.map((post, index) => ({
35+
"@type": "ListItem",
36+
"position": index + 1,
37+
"item": {
38+
"@type": "BlogPosting",
39+
"headline": post.data.title,
40+
"description": post.data.description,
41+
"author": {
42+
"@type": "Person",
43+
"name": "Jeremy Wong",
44+
"url": "https://craftbyzen.com/"
45+
},
46+
"datePublished": post.data.pubDate,
47+
"url": `https://craftbyzen.com/blog/${post.slug}`
48+
}
49+
}))
50+
}
51+
};
52+
}
53+
54+
export default {
55+
generateWritingPieceSchema,
56+
};

0 commit comments

Comments
 (0)