Skip to content

Commit

Permalink
feat: improve opengraph information generation
Browse files Browse the repository at this point in the history
  • Loading branch information
a11rew committed Oct 15, 2024
1 parent 883a6a1 commit d3da507
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 118 deletions.
2 changes: 1 addition & 1 deletion starters/nextjs-starter-approuter-ts/app/articles/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ export default async function ArticlesListTemplate() {
export function generateMetadata() {
return {
title: "Decoupled Next PCC Demo",
description: "Generated by create-pantheon-decoupled-kit.",
description: "Articles",
};
}
2 changes: 1 addition & 1 deletion starters/nextjs-starter-approuter-ts/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,6 @@ export default async function Home() {
export function generateMetadata() {
return {
title: "Decoupled Next PCC Demo",
description: "Generated by create-pantheon-decoupled-kit.",
description: "Homepage",
};
}
49 changes: 25 additions & 24 deletions starters/nextjs-starter-approuter-ts/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ArticleWithoutContent } from "@pantheon-systems/pcc-react-sdk";
import { clsx, type ClassValue } from "clsx";
import { Metadata } from "next";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
Expand All @@ -15,46 +16,46 @@ export function formatDate(input: string | number): string {
});
}

interface DateInputObject {
msSinceEpoch: string;
}

function isDateInputObject(v: DateInputObject | unknown): v is DateInputObject {
return (v as DateInputObject).msSinceEpoch != null;
}

export function getSeoMetadata(article: ArticleWithoutContent) {
const tags = article.tags && article.tags.length > 0 ? article.tags : [];
let authors = [];
let publishedTime = null;

// Collecting data from metadata fields
Object.entries(article.metadata || {}).forEach(([key, val]) => {
if (key.toLowerCase().trim() === "author" && val) authors = [val];
else if (key.toLowerCase().trim() === "date" && isDateInputObject(val))
publishedTime = new Date(val.msSinceEpoch).toISOString();
});

export function getSeoMetadata(article: ArticleWithoutContent): Metadata {
const tags: string[] =
article.tags && article.tags.length > 0 ? article.tags : [];
const imageProperties = [
article.metadata?.image,
article.metadata?.["Hero Image"],
// Extend as needed
]
.filter((url): url is string => typeof url === "string")
.map((url) => ({ url }));
const description = article.metadata?.description
? String(article.metadata?.description)
: "Article hosted using Pantheon Content Cloud";

let authors: Metadata["authors"] = [];

const description = "Article hosted using Pantheon Content Publisher";
// Collecting data from metadata fields
Object.entries(article.metadata || {}).forEach(([k, v]) => {
const key = k.toLowerCase().trim();

switch (key) {
case "author": {
if (typeof v === "string") {
authors = [{ name: v }];
}
break;
}
}
});

return {
title: article.title,
description,
tags,
keywords: tags,
authors,
publishedTime,
openGraph: {
type: "website",
title: article.title,
description,
images: imageProperties,
description,
},
};
}
61 changes: 45 additions & 16 deletions starters/nextjs-starter-ts/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ArticleWithoutContent } from "@pantheon-systems/pcc-react-sdk";
import { clsx, type ClassValue } from "clsx";
import { OpenGraph } from "next-seo/lib/types";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
Expand All @@ -24,30 +25,58 @@ function isDateInputObject(v: DateInputObject | unknown): v is DateInputObject {
}

export function getSeoMetadata(article: ArticleWithoutContent) {
const tags = article.tags && article.tags.length > 0 ? article.tags : [];
let authors = [];
let publishedTime = null;

// Collecting data from metadata fields
Object.entries(article.metadata || {}).forEach(([key, val]) => {
if (key.toLowerCase().trim() === "author" && val) authors = [val];
else if (key.toLowerCase().trim() === "date" && isDateInputObject(val))
publishedTime = new Date(val.msSinceEpoch).toISOString();
});

const tags: string[] =
article.tags && article.tags.length > 0 ? article.tags : [];
const imageProperties = [
article.metadata?.image,
article.metadata?.["Hero Image"],
// Extend as needed
]
.filter((url): url is string => typeof url === "string")
.map((url) => ({ url }));
const description = article.metadata?.description
? String(article.metadata?.description)
: "Article hosted using Pantheon Content Cloud";

let authors: string[] = [];
let publishedTime: number | null = article.publishedDate;

// Collecting data from metadata fields
Object.entries(article.metadata || {}).forEach(([k, v]) => {
const key = k.toLowerCase().trim();

switch (key) {
case "author": {
if (typeof v === "string") {
authors = [v];
}
break;
}
case "date": {
if (isDateInputObject(v)) {
// Prefer the date from the metadata, if it exists
publishedTime = parseInt(v.msSinceEpoch);
}
break;
}
}
});

return {
title: article.title,
description: "Article hosted using Pantheon Content Cloud",
tags,
authors,
publishedTime,
images: imageProperties,
description,
openGraph: {
type: "website",
title: article.title,
images: imageProperties,
description,
article: {
authors: authors,
tags: tags,
...(publishedTime && {
publishedTime: new Date(publishedTime).toISOString(),
}),
},
} satisfies OpenGraph,
};
}
14 changes: 1 addition & 13 deletions starters/nextjs-starter-ts/pages/articles/[...uri].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,7 @@ export default function ArticlePage({ article, grant }: ArticlePageProps) {
<NextSeo
title={seoMetadata.title}
description={seoMetadata.description}
openGraph={{
type: "website",
title: seoMetadata.title,
description: seoMetadata.description,
images: seoMetadata.images,
article: {
authors: seoMetadata.authors,
tags: seoMetadata.tags,
...(seoMetadata.publishedTime && {
publishedTime: seoMetadata.publishedTime,
}),
},
}}
openGraph={seoMetadata.openGraph}
/>

<div className="prose mx-4 mt-16 text-black sm:mx-6 md:mx-auto">
Expand Down
24 changes: 2 additions & 22 deletions starters/nextjs-starter-ts/pages/examples/ssg-isr/[uri].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,22 @@ import {
import { GetStaticPaths, GetStaticProps } from "next";
import { NextSeo } from "next-seo";
import { StaticArticleView } from "../../../components/article-view";
import { ArticleGrid } from "../../../components/grid";
import Layout from "../../../components/layout";
import { getSeoMetadata } from "../../../lib/utils";

interface ArticlePageProps {
article: Article;
recommendedArticles: Article[];
}

export default function ArticlePage({
article,
recommendedArticles,
}: ArticlePageProps) {
export default function ArticlePage({ article }: ArticlePageProps) {
const seoMetadata = getSeoMetadata(article);

return (
<Layout>
<NextSeo
title={seoMetadata.title}
description={seoMetadata.description}
openGraph={{
type: "website",
title: seoMetadata.title,
description: seoMetadata.description,
article: {
authors: seoMetadata.authors,
tags: seoMetadata.tags,
...(seoMetadata.publishedTime && {
publishedTime: seoMetadata.publishedTime,
}),
},
}}
openGraph={seoMetadata.openGraph}
/>

<div className="prose mx-4 mt-16 text-black sm:mx-6 md:mx-auto">
Expand Down Expand Up @@ -64,13 +48,9 @@ export const getStaticProps: GetStaticProps<{}, { uri: string }> = async ({
};
}

const recommendedArticles =
await PCCConvenienceFunctions.getRecommendedArticles(article.id);

return {
props: {
article,
recommendedArticles,
},
};
} catch (e) {
Expand Down
57 changes: 42 additions & 15 deletions starters/nextjs-starter/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,56 @@ function isDateInputObject(v) {

export function getSeoMetadata(article) {
const tags = article.tags && article.tags.length > 0 ? article.tags : [];
let authors = [];
let publishedTime = null;

// Collecting data from metadata fields
Object.entries(article.metadata || {}).forEach(([key, val]) => {
if (key.toLowerCase().trim() === "author" && val) authors = [val];
else if (key.toLowerCase().trim() === "date" && isDateInputObject(val))
publishedTime = new Date(val.msSinceEpoch).toISOString();
});

const imageProperties = [
article.metadata?.image,
article.metadata?.["Hero Image"],
// Extend as needed
]
.filter((url) => typeof url === "string")
.map((url) => ({ url }));
const description = article.metadata?.description
? String(article.metadata?.description)
: "Article hosted using Pantheon Content Cloud";

let authors = [];
let publishedTime = article.publishedDate;

// Collecting data from metadata fields
Object.entries(article.metadata || {}).forEach(([k, v]) => {
const key = k.toLowerCase().trim();

switch (key) {
case "author": {
if (typeof v === "string") {
authors = [v];
}
break;
}
case "date": {
if (isDateInputObject(v)) {
// Prefer the date from the metadata, if it exists
publishedTime = parseInt(v.msSinceEpoch);
}
break;
}
}
});

return {
title: article.title,
description: "Article hosted using Pantheon Content Cloud",
tags,
authors,
publishedTime,
images: imageProperties,
description,
openGraph: {
type: "website",
title: article.title,
images: imageProperties,
description,
article: {
authors: authors,
tags: tags,
...(publishedTime && {
publishedTime: new Date(publishedTime).toISOString(),
}),
},
},
};
}
14 changes: 1 addition & 13 deletions starters/nextjs-starter/pages/articles/[...uri].jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,7 @@ export default function ArticlePage({ article, grant }) {
<NextSeo
title={seoMetadata.title}
description={seoMetadata.description}
openGraph={{
type: "website",
title: seoMetadata.title,
description: seoMetadata.description,
images: seoMetadata.images,
article: {
authors: seoMetadata.authors,
tags: seoMetadata.tags,
...(seoMetadata.publishedTime && {
publishedTime: seoMetadata.publishedTime,
}),
},
}}
openGraph={seoMetadata.openGraph}
/>

<div className="prose mx-4 mt-16 text-black sm:mx-6 md:mx-auto">
Expand Down
14 changes: 1 addition & 13 deletions starters/nextjs-starter/pages/examples/ssg-isr/[uri].jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { PCCConvenienceFunctions } from "@pantheon-systems/pcc-react-sdk";
import { NextSeo } from "next-seo";
import { StaticArticleView } from "../../../components/article-view";
import { ArticleGrid } from "../../../components/grid";
import Layout from "../../../components/layout";
import { getSeoMetadata } from "../../../lib/utils";

Expand All @@ -13,18 +12,7 @@ export default function ArticlePage({ article, recommendedArticles }) {
<NextSeo
title={seoMetadata.title}
description={seoMetadata.description}
openGraph={{
type: "website",
title: seoMetadata.title,
description: seoMetadata.description,
article: {
authors: seoMetadata.authors,
tags: seoMetadata.tags,
...(seoMetadata.publishedTime && {
publishedTime: seoMetadata.publishedTime,
}),
},
}}
openGraph={seoMetadata.openGraph}
/>

<div className="prose mx-4 mt-16 text-black sm:mx-6 md:mx-auto">
Expand Down

0 comments on commit d3da507

Please sign in to comment.