diff --git a/app/blog/[slug]/page.js b/app/blog/[slug]/page.js index 886deda..2fcb45f 100644 --- a/app/blog/[slug]/page.js +++ b/app/blog/[slug]/page.js @@ -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,66 +87,186 @@ 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 ( -
- {/* Content Banner */} - - - {/* Decorative Shapes */} - {/* Right Side Shape (3/4 up the page) */} -
- {/* eslint-disable-next-line @next/next/no-img-element */} - -
- - {/* Left Side Shape (3/4 down the page) */} -
- {/* eslint-disable-next-line @next/next/no-img-element */} - -
- - {/* Main Content */} -
- {/* Article Content */} -
-
-
-
- - {/* Related Articles Section */} - + {/* Structured Data */} +