Content Page #19

Merged
an.di merged 48 commits from adilallo/feature/Blog into main 2025-09-18 15:44:46 +00:00
Showing only changes of commit 0f9bc0d74e - Show all commits
+130 -2
View File
@@ -55,6 +55,14 @@ export async function generateMetadata({ params }) {
type: "article",
publishedTime: post.frontmatter.date,
authors: [post.frontmatter.author],
url: `https://communityrule.com/blog/${slug}`,
siteName: "CommunityRule",
},
twitter: {
card: "summary_large_image",
title: post.frontmatter.title,
description: post.frontmatter.description,
creator: "@communityrule",
},
};
} catch (error) {
@@ -79,11 +87,130 @@ export default async function BlogPostPage({ params }) {
notFound();
}
// Get related articles (for now, just get other posts)
// Get related articles with improved algorithm
const allPosts = getAllPosts();
const relatedArticles = allPosts; // Pass all posts to RelatedArticles component for filtering
// Simple related articles algorithm based on content similarity
const getRelatedArticles = (currentPost, allPosts, limit = 3) => {
const otherPosts = allPosts.filter((p) => p.slug !== currentPost.slug);
// Score posts based on content similarity
const scoredPosts = otherPosts.map((post) => {
let score = 0;
// Check for similar keywords in title and description
const currentTitle = currentPost.frontmatter.title.toLowerCase();
const currentDesc = currentPost.frontmatter.description.toLowerCase();
const postTitle = post.frontmatter.title.toLowerCase();
const postDesc = post.frontmatter.description.toLowerCase();
// Common keywords that indicate similarity
const keywords = [
"community",
"conflict",
"decision",
"governance",
"security",
"trust",
"collaboration",
"organization",
];
keywords.forEach((keyword) => {
if (currentTitle.includes(keyword) && postTitle.includes(keyword))
score += 3;
if (currentDesc.includes(keyword) && postDesc.includes(keyword))
score += 2;
if (currentTitle.includes(keyword) && postDesc.includes(keyword))
score += 1;
if (currentDesc.includes(keyword) && postTitle.includes(keyword))
score += 1;
});
return { ...post, score };
});
// Sort by score and return top posts
return scoredPosts
.sort((a, b) => b.score - a.score)
.slice(0, limit)
.map(({ score, ...post }) => post); // Remove score from final result
};
const relatedArticles = getRelatedArticles(post, allPosts);
// Generate structured data for search engines
const structuredData = {
"@context": "https://schema.org",
"@type": "Article",
headline: post.frontmatter.title,
description: post.frontmatter.description,
author: {
"@type": "Person",
name: post.frontmatter.author,
},
publisher: {
"@type": "Organization",
name: "CommunityRule",
url: "https://communityrule.com",
logo: {
"@type": "ImageObject",
url: "https://communityrule.com/assets/Logo.svg",
},
},
datePublished: post.frontmatter.date,
dateModified: post.frontmatter.date,
mainEntityOfPage: {
"@type": "WebPage",
"@id": `https://communityrule.com/blog/${post.slug}`,
},
url: `https://communityrule.com/blog/${post.slug}`,
articleSection: "Community Building",
keywords: ["community", "governance", "decision making", "collaboration"],
};
// Breadcrumb structured data
const breadcrumbData = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: [
{
"@type": "ListItem",
position: 1,
name: "Home",
item: "https://communityrule.com",
},
{
"@type": "ListItem",
position: 2,
name: "Blog",
item: "https://communityrule.com/blog",
},
{
"@type": "ListItem",
position: 3,
name: post.frontmatter.title,
item: `https://communityrule.com/blog/${post.slug}`,
},
],
};
return (
<>
{/* Structured Data */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(structuredData),
}}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(breadcrumbData),
}}
/>
<div className="min-h-screen bg-[#F4F3F1] relative overflow-hidden">
{/* Content Banner */}
<ContentBanner post={post} />
@@ -140,5 +267,6 @@ export default async function BlogPostPage({ params }) {
{/* Ask Organizer Section */}
<AskOrganizer {...askOrganizerData} variant="inverse" />
</div>
</>
);
}