Skip to content

Commit 1969914

Browse files
authored
feat: add reading time and article section metadata for improved SEO
1 parent 646ab80 commit 1969914

File tree

4 files changed

+50
-9
lines changed

4 files changed

+50
-9
lines changed

src/components/HeadSEO.astro

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ type Props = {
99
robots?: string;
1010
keywords?: string;
1111
twitterHandle?: string;
12+
readingTime?: string;
1213
structuredData?: Record<string, unknown>;
1314
};
1415
@@ -21,6 +22,7 @@ const {
2122
author = "Avaab Razzaq",
2223
robots = "index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1",
2324
keywords,
25+
readingTime,
2426
structuredData,
2527
} = Astro.props as Props;
2628
---
@@ -73,8 +75,17 @@ const {
7375
<meta name="twitter:image:alt" content={title} />
7476
<meta name="twitter:label1" content="Built by" />
7577
<meta name="twitter:data1" content="Avaab Razzaq" />
76-
<meta name="twitter:label2" content="Based in" />
77-
<meta name="twitter:data2" content="Miami, FL" />
78+
{readingTime ? (
79+
<>
80+
<meta name="twitter:label2" content="Reading time" />
81+
<meta name="twitter:data2" content={`${readingTime} min read`} />
82+
</>
83+
) : (
84+
<>
85+
<meta name="twitter:label2" content="Based in" />
86+
<meta name="twitter:data2" content="Miami, FL" />
87+
</>
88+
)}
7889

7990
<meta name="theme-color" content="#000000" media="(prefers-color-scheme: dark)" />
8091
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)" />

src/layouts/BaseLayout.astro

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type Props = {
1616
canonicalUrl?: string;
1717
ogImage?: string;
1818
ogType?: "website" | "article" | "profile";
19+
articleSection?: string;
1920
structuredData?: Record<string, unknown>;
2021
noIndex?: boolean;
2122
keywords?: string;
@@ -34,11 +35,13 @@ const {
3435
canonicalUrl: canonicalUrlProp,
3536
ogImage = new URL("/og-ai-growth-engineer.png", siteUrl).toString(),
3637
ogType = "website",
38+
articleSection,
3739
structuredData,
3840
noIndex = false,
3941
keywords,
4042
publishedTime,
4143
modifiedTime,
44+
readingTime,
4245
author = "Avaab Razzaq",
4346
robots,
4447
} = Astro.props as Props;
@@ -83,6 +86,7 @@ const currentPath = Astro.url.pathname;
8386
author={author}
8487
robots={resolvedRobots}
8588
keywords={finalKeywords}
89+
readingTime={readingTime}
8690
structuredData={structuredData}
8791
/>
8892

@@ -91,6 +95,7 @@ const currentPath = Astro.url.pathname;
9195
{publishedTime && <meta property="article:published_time" content={publishedTime} />}
9296
{publishedTime && <meta property="article:author" content={author} />}
9397
{modifiedTime && <meta property="article:modified_time" content={modifiedTime} />}
98+
{articleSection && <meta property="article:section" content={articleSection} />}
9499

95100
<script is:inline set:html={themeInitScript}></script>
96101
</head>

src/pages/about/index.astro

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ const structuredData = {
9696
"https://github.com/AR10Dev",
9797
"https://linkedin.com/in/avaab-razzaq-937b89366",
9898
"https://twitter.com/itsmeAvaab",
99+
"https://x.com/itsmeAvaab",
99100
],
100101
address: {
101102
"@type": "PostalAddress",
@@ -116,6 +117,32 @@ const structuredData = {
116117
hasOccupation: {
117118
"@type": "Occupation",
118119
name: "AI Growth Engineer",
120+
description:
121+
"Builds AI automation systems, full-stack web applications, and implements technical SEO strategies that drive organic growth for businesses.",
122+
occupationalCategory: "15-1299.09",
123+
occupationLocation: {
124+
"@type": "City",
125+
name: "Miami",
126+
containedInPlace: {
127+
"@type": "State",
128+
name: "Florida",
129+
containedInPlace: {
130+
"@type": "Country",
131+
name: "United States",
132+
},
133+
},
134+
},
135+
estimatedSalary: {
136+
"@type": "MonetaryAmountDistribution",
137+
name: "base",
138+
currency: "USD",
139+
duration: "P1H",
140+
percentile10: 150,
141+
percentile25: 175,
142+
median: 200,
143+
percentile75: 250,
144+
percentile90: 300,
145+
},
119146
},
120147
hasCredential: credentials.map((cred) => ({
121148
"@type": "EducationalOccupationalCredential",

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

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,10 @@ function formatDate(date: Date): string {
146146
// Calculate reading time if not in frontmatter
147147
const wordCount = (post.body ?? "").split(/\s+/).filter(Boolean).length;
148148
const readingTimeMinutes = post.data.readingTime || Math.ceil(wordCount / 200);
149-
const readingTimeString = `${readingTimeMinutes} ${readingTimeMinutes === 1 ? "minute" : "minutes"}`;
150149
151150
const publishedTimeISO = post.data.publishDate
152151
? new Date(post.data.publishDate).toISOString()
153-
: null;
152+
: undefined;
154153
155154
const modifiedTimeISO = post.data.updatedDate
156155
? new Date(post.data.updatedDate).toISOString()
@@ -294,14 +293,13 @@ const structuredData = {
294293
canonicalUrl={canonicalUrl}
295294
ogImage={ogImage}
296295
ogType="article"
297-
publishedTime={publishedTimeISO ?? undefined}
298-
modifiedTime={modifiedTimeISO ?? undefined}
296+
publishedTime={publishedTimeISO}
297+
modifiedTime={modifiedTimeISO}
298+
articleSection={articleSection}
299299
author={articleAuthorUrl}
300-
readingTime={readingTimeString}
300+
readingTime={post.data.readingTime ? String(post.data.readingTime) : undefined}
301301
structuredData={structuredData}
302302
>
303-
<meta slot="head" property="article:section" content={articleSection} />
304-
305303
<article class="min-h-screen py-12">
306304
<div class={CONTAINER_CLASSES.section}>
307305
<div class="mx-auto max-w-3xl">

0 commit comments

Comments
 (0)