@@ -79,12 +79,13 @@ const { post, relatedService, relatedPosts, relatedPortfolio } = Astro.props;
7979const { Content, headings } = await render (post );
8080
8181const siteUrl = " https://avaabrazzaq.com" ;
82+ const postUrl = new URL (` /blog/${post .id }/ ` , siteUrl ).toString ();
8283const title = ` ${post .data .title } | Blog - Avaab Razzaq ` ;
8384const description = post .data .description ;
84- const canonicalUrl = new URL ( ` /blog/${ post . id }/ ` , siteUrl ). toString () ;
85+ const canonicalUrl = postUrl ;
8586const ogImage =
8687 post .data .image ?.src ??
87- new URL (" /og-ai-growth-engineer.svg " , siteUrl ).toString ();
88+ new URL (" /og-ai-growth-engineer.png " , siteUrl ).toString ();
8889
8990// Format date helper
9091function formatDate(date : Date ): string {
@@ -97,7 +98,8 @@ function formatDate(date: Date): string {
9798
9899// Calculate reading time if not in frontmatter
99100const wordCount = (post .body ?? " " ).split (/ \s + / ).filter (Boolean ).length ;
100- const readingTime = post .data .readingTime || Math .ceil (wordCount / 200 );
101+ const readingTimeMinutes = post .data .readingTime || Math .ceil (wordCount / 200 );
102+ const readingTimeString = ` ${readingTimeMinutes } ${readingTimeMinutes === 1 ? " minute" : " minutes" } ` ;
101103
102104// Build the structured data graph
103105const structuredDataGraph: Record <string , unknown >[] = [
@@ -108,27 +110,21 @@ const structuredDataGraph: Record<string, unknown>[] = [
108110 name: " Avaab Razzaq - AI Growth Engineer" ,
109111 description:
110112 " AI Growth Engineer specializing in web apps, AI automation, and technical SEO" ,
111- publisher: { " @id" : ` ${siteUrl }/#person ` },
113+ publisher: { " @id" : ` ${siteUrl }/#organization ` },
112114 },
113115 {
114- " @type" : " WebPage" ,
115- " @id" : canonicalUrl ,
116- url: canonicalUrl ,
117- name: title ,
118- description: description ,
119- isPartOf: { " @id" : ` ${siteUrl }/#website ` },
120- breadcrumb: {
121- " @type" : " BreadcrumbList" ,
122- itemListElement: [
123- { " @type" : " ListItem" , position: 1 , name: " Home" , item: siteUrl },
124- {
125- " @type" : " ListItem" ,
126- position: 2 ,
127- name: " Blog" ,
128- item: ` ${siteUrl }/blog/ ` ,
129- },
130- { " @type" : " ListItem" , position: 3 , name: post .data .title },
131- ],
116+ " @type" : " Organization" ,
117+ " @id" : ` ${siteUrl }/#organization ` ,
118+ name: " Avaab Razzaq - AI Growth Engineer" ,
119+ url: siteUrl ,
120+ logo: {
121+ " @type" : " ImageObject" ,
122+ " @id" : ` ${siteUrl }/#logo ` ,
123+ url: ` ${siteUrl }/pwa-512x512.png ` ,
124+ contentUrl: ` ${siteUrl }/pwa-512x512.png ` ,
125+ width: 512 ,
126+ height: 512 ,
127+ caption: " Avaab Razzaq - AI Growth Engineer" ,
132128 },
133129 },
134130 {
@@ -143,29 +139,51 @@ const structuredDataGraph: Record<string, unknown>[] = [
143139 ],
144140 },
145141 {
146- " @type" : " BlogPosting" ,
147- " @id" : ` ${canonicalUrl }#article ` ,
142+ " @type" : " Article" ,
143+ " @id" : ` ${postUrl }#article ` ,
144+ isPartOf: { " @id" : postUrl },
145+ author: {
146+ name: " Avaab Razzaq" ,
147+ " @id" : ` ${siteUrl }/#person ` ,
148+ },
148149 headline: post .data .title ,
149- description: post .data .description ,
150- author: { " @id" : ` ${siteUrl }/#person ` },
151- publisher: { " @id" : ` ${siteUrl }/#person ` },
152150 datePublished: post .data .publishDate .toISOString (),
153- ... (post .data .updatedDate && {
154- dateModified: post .data .updatedDate .toISOString (),
155- }),
156- ... (post .data .image && {
157- image: {
158- " @type" : " ImageObject" ,
159- url: post .data .image .src ,
160- caption: post .data .image .alt ,
161- },
162- }),
163- mainEntityOfPage: { " @id" : canonicalUrl },
151+ dateModified: (post .data .updatedDate ?? post .data .publishDate ).toISOString (),
152+ mainEntityOfPage: { " @id" : postUrl },
153+ wordCount: wordCount ,
154+ publisher: { " @id" : ` ${siteUrl }/#organization ` },
155+ inLanguage: " en-US" ,
156+ image: post .data .image ?.src ?? ` ${siteUrl }/og-blog.png ` ,
164157 keywords: post .data .tags .join (" , " ),
165158 articleSection: post .data .category ,
159+ timeRequired: ` PT${readingTimeMinutes }M ` ,
160+ },
161+ {
162+ " @type" : " WebPage" ,
163+ " @id" : postUrl ,
164+ url: postUrl ,
165+ name: post .data .title ,
166+ isPartOf: { " @id" : ` ${siteUrl }/#website ` },
167+ datePublished: post .data .publishDate .toISOString (),
168+ dateModified: (post .data .updatedDate ?? post .data .publishDate ).toISOString (),
169+ description: post .data .description ,
170+ breadcrumb: { " @id" : ` ${postUrl }#breadcrumb ` },
166171 inLanguage: " en-US" ,
167- wordCount: wordCount ,
168- timeRequired: ` PT${readingTime }M ` ,
172+ potentialAction: [
173+ {
174+ " @type" : " ReadAction" ,
175+ target: [postUrl ],
176+ },
177+ ],
178+ },
179+ {
180+ " @type" : " BreadcrumbList" ,
181+ " @id" : ` ${postUrl }#breadcrumb ` ,
182+ itemListElement: [
183+ { " @type" : " ListItem" , position: 1 , name: " Home" , item: siteUrl },
184+ { " @type" : " ListItem" , position: 2 , name: " Blog" , item: ` ${siteUrl }/blog/ ` },
185+ { " @type" : " ListItem" , position: 3 , name: post .data .title },
186+ ],
169187 },
170188];
171189
@@ -208,6 +226,7 @@ const structuredData = {
208226 publishedTime ={ post .data .publishDate .toISOString ()}
209227 modifiedTime ={ post .data .updatedDate ?.toISOString ()}
210228 author ={ post .data .author }
229+ readingTime ={ readingTimeString }
211230 structuredData ={ structuredData }
212231>
213232 <article class =" min-h-screen py-12" >
@@ -286,7 +305,7 @@ const structuredData = {
286305 <circle cx =" 12" cy =" 12" r =" 10" ></circle >
287306 <polyline points =" 12 6 12 12 16 14" ></polyline >
288307 </svg >
289- <span >{ readingTime } min read</span >
308+ <span >{ readingTimeMinutes } min read</span >
290309 </div >
291310 </div >
292311
0 commit comments