Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions app/blog/[slug]/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export async function generateMetadata({ params }) {
siteName: SITE.name,
images: [{ url: ogImage, width: 1200, height: 630, alt: post.title }],
publishedTime: post.datePublished,
...(post.dateModified ? { modifiedTime: post.dateModified } : {}),
authors: post.authors.map((a) => a.name),
tags: post.tags,
},
Expand All @@ -61,6 +62,18 @@ function formatDate(iso) {
return new Date(iso).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });
}

// Frontmatter `about:` / `mentions:` entry -> schema.org node. `type` defaults
// to Thing; any extra keys (applicationCategory, description, ...) pass through.
function entityLd({ type, name, url, sameAs, ...rest }) {
return {
'@type': type || 'Thing',
name,
...(url ? { url } : {}),
...(Array.isArray(sameAs) && sameAs.length ? { sameAs } : {}),
...rest,
};
}

export default async function BlogPost({ params }) {
const post = getPostBySlug(params.slug);
if (!post) notFound();
Expand All @@ -83,7 +96,7 @@ export default async function BlogPost({ params }) {
description: post.seoDescription || undefined,
image: [ogImage],
datePublished: post.datePublished,
dateModified: post.datePublished,
dateModified: post.dateModified || post.datePublished,
inLanguage: 'en-US',
isAccessibleForFree: true,
author: post.authors.map((a) => ({
Expand Down Expand Up @@ -113,7 +126,13 @@ export default async function BlogPost({ params }) {
wordCount: post.words,
timeRequired: `PT${post.readMinutes}M`,
articleSection: post.tags[0] || 'Cloud Native',
about: post.tags.map((t) => ({ '@type': 'Thing', name: t })),
about: [
...post.about.map(entityLd),
...post.tags
.filter((t) => !post.about.some((e) => e.name.toLowerCase() === t.toLowerCase()))
.map((t) => ({ '@type': 'Thing', name: t })),
],
...(post.mentions.length ? { mentions: post.mentions.map(entityLd) } : {}),
...(seriesInfo
? {
isPartOf: {
Expand Down Expand Up @@ -233,6 +252,14 @@ export default async function BlogPost({ params }) {
))}
<span className="mx-2">·</span>
<time dateTime={post.datePublished}>{formatDate(post.datePublished)}</time>
{post.dateModified && (
<>
<span className="mx-2">·</span>
<span>
Updated <time dateTime={post.dateModified}>{formatDate(post.dateModified)}</time>
</span>
</>
)}
<span className="mx-2">·</span>
<span>{post.readMinutes} min read</span>
</div>
Expand Down
577 changes: 577 additions & 0 deletions content/blog/kubernetes-observability-in-2026-with-openobserve.md

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions lib/blog.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,15 @@ function loadAll() {
faq: Array.isArray(data.faq)
? data.faq.filter((x) => x && x.q && x.a)
: [],
// Optional schema.org entities for the BlogPosting JSON-LD. `about:`
// entries replace the generic tag-derived Thing of the same name (e.g. a
// SoftwareApplication with sameAs links for the product a post covers);
// `mentions:` lists other named things the post discusses. Each entry is
// {type, name, url, sameAs, ...extra schema.org properties}.
about: Array.isArray(data.about) ? data.about.filter((x) => x && x.name) : [],
mentions: Array.isArray(data.mentions) ? data.mentions.filter((x) => x && x.name) : [],
// Optional `dateModified:`; the JSON-LD falls back to datePublished.
dateModified: data.dateModified || null,
readMinutes: Math.max(1, Math.round(stats.minutes)),
words: stats.words,
content,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading