From a26b775b7bbf1abd3e99c8bf9ce4c7522d3a0adc Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
Date: Wed, 19 Jan 2022 13:56:34 +0100
Subject: chore: add structured data using schema.org and JSON-LD

I also added the featured image on single article.
---
 src/components/PostPreview/PostPreview.tsx | 104 +++++++++++++++++++----------
 1 file changed, 70 insertions(+), 34 deletions(-)

(limited to 'src/components/PostPreview/PostPreview.tsx')

diff --git a/src/components/PostPreview/PostPreview.tsx b/src/components/PostPreview/PostPreview.tsx
index 3bf7bdb..2a0bcf1 100644
--- a/src/components/PostPreview/PostPreview.tsx
+++ b/src/components/PostPreview/PostPreview.tsx
@@ -7,6 +7,9 @@ import Image from 'next/image';
 import { ButtonLink } from '@components/Buttons';
 import { ArrowIcon } from '@components/Icons';
 import { TitleLevel } from '@ts/types/app';
+import { BlogPosting, WithContext } from 'schema-dts';
+import Head from 'next/head';
+import { config } from '@config/website';
 
 const PostPreview = ({
   post,
@@ -24,41 +27,74 @@ const PostPreview = ({
     thematics: post.thematics,
   };
 
+  const publicationDate = new Date(post.dates.publication);
+  const updateDate = new Date(post.dates.update);
+
+  const schemaJsonLd: WithContext<BlogPosting> = {
+    '@context': 'https://schema.org',
+    '@type': 'BlogPosting',
+    name: post.title,
+    description: post.intro,
+    articleBody: post.intro,
+    author: { '@id': `${config.url}/#branding` },
+    commentCount: post.commentCount ? post.commentCount : 0,
+    copyrightYear: publicationDate.getFullYear(),
+    creator: { '@id': `${config.url}/#branding` },
+    dateCreated: publicationDate.toISOString(),
+    dateModified: updateDate.toISOString(),
+    datePublished: publicationDate.toISOString(),
+    editor: { '@id': `${config.url}/#branding` },
+    image: post.featuredImage?.sourceUrl,
+    inLanguage: config.defaultLocale,
+    isBasedOn: `${config.url}/article/${post.slug}`,
+    isPartOf: { '@id': `${config.url}/blog` },
+    license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr',
+    thumbnailUrl: post.featuredImage?.sourceUrl,
+  };
+
   return (
-    <article className={styles.wrapper}>
-      {post.featuredImage && Object.keys(post.featuredImage).length > 0 && (
-        <div className={styles.cover}>
-          <Image
-            src={post.featuredImage.sourceUrl}
-            alt={post.featuredImage.altText}
-            layout="fill"
-            objectFit="contain"
-          />
-        </div>
-      )}
-      <header className={styles.header}>
-        <TitleTag className={styles.title}>
-          <Link href={`/article/${post.slug}`}>
-            <a>{post.title}</a>
-          </Link>
-        </TitleTag>
-      </header>
-      <div
-        className={styles.body}
-        dangerouslySetInnerHTML={{ __html: post.intro }}
-      ></div>
-      <footer className={styles.footer}>
-        <ButtonLink target={`/article/${post.slug}`} position="left">
-          {t`Read more`}
-          <span className="screen-reader-text">
-            {' '}
-            {t({ message: `about ${post.title}`, comment: 'Post title' })}
-          </span>
-          <ArrowIcon />
-        </ButtonLink>
-      </footer>
-      <PostMeta meta={meta} />
-    </article>
+    <>
+      <Head>
+        <script
+          type="application/ld+json"
+          dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaJsonLd) }}
+        ></script>
+      </Head>
+      <article className={styles.wrapper}>
+        {post.featuredImage && Object.keys(post.featuredImage).length > 0 && (
+          <div className={styles.cover}>
+            <Image
+              src={post.featuredImage.sourceUrl}
+              alt={post.featuredImage.altText}
+              layout="fill"
+              objectFit="contain"
+            />
+          </div>
+        )}
+        <header className={styles.header}>
+          <TitleTag className={styles.title}>
+            <Link href={`/article/${post.slug}`}>
+              <a>{post.title}</a>
+            </Link>
+          </TitleTag>
+        </header>
+        <div
+          className={styles.body}
+          dangerouslySetInnerHTML={{ __html: post.intro }}
+        ></div>
+        <footer className={styles.footer}>
+          <ButtonLink target={`/article/${post.slug}`} position="left">
+            {t`Read more`}
+            <span className="screen-reader-text">
+              {' '}
+              {t({ message: `about ${post.title}`, comment: 'Post title' })}
+            </span>
+            <ArrowIcon />
+          </ButtonLink>
+        </footer>
+        <PostMeta meta={meta} />
+      </article>
+    </>
   );
 };
 
-- 
cgit v1.2.3

