SEO blog post V2

This commit is contained in:
2026-08-05 22:28:34 +02:00
parent 8c50bf71c5
commit ca605f8852
7 changed files with 7456 additions and 8477 deletions

5
.gitignore vendored
View File

@@ -77,6 +77,11 @@ meta-fix.js
read-inbox.mjs
quora_antwort_statisch_dynamisch.txt
# Local blog audit reports and temporary snapshots
scratch_blog_analysis.json
scratch_scored_blog_posts.json
src/lib/blog-data.snapshot-*.ts
# Local developer-package workspaces and unreferenced generated media
/packages/
/public/Events/

5569
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,7 @@ import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/Card';
import { Badge } from '@/components/ui/Badge';
import Breadcrumbs, { BreadcrumbItem } from '@/components/Breadcrumbs';
import { blogPosts } from '@/lib/blog-data';
import { REDIRECTED_BLOG_SLUGS } from "@/lib/content";
// Enable Incremental Static Regeneration (ISR)
// Revalidate every hour
@@ -63,6 +64,7 @@ export default function BlogPage() {
const publishedPosts = blogPosts
.filter(post => {
if (REDIRECTED_BLOG_SLUGS.has(post.slug)) return false;
const publishDate = post.datePublished ? new Date(post.datePublished) : new Date(post.date);
return publishDate <= currentDate;
})

View File

@@ -1,5 +1,6 @@
import { MetadataRoute } from 'next';
import { blogPosts } from '../lib/blog-data';
import { REDIRECTED_BLOG_SLUGS } from '../lib/content';
import { pillarMeta } from '../lib/pillar-data';
import { authors } from '../lib/author-data';
import { industryPages } from '../lib/industry-pages';
@@ -42,6 +43,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
// Filter out future posts so Google doesn't see them
const blogPages = blogPosts
.filter((post) => {
if (REDIRECTED_BLOG_SLUGS.has(post.slug)) return false;
const publishDate = post.datePublished
? new Date(post.datePublished)
: new Date(post.date);

File diff suppressed because it is too large Load Diff

View File

@@ -2,10 +2,27 @@ import { blogPosts } from "./blog-data";
import { authors } from "./author-data";
import type { BlogPost, PillarKey, AuthorProfile } from "./types";
/**
* Blog slugs that are 301-redirected in next.config.mjs.
* They must not appear in the blog index, the learn pillars, the sitemap
* or IndexNow submissions - linking to a redirect source wastes crawl budget
* and passes link equity through an unnecessary hop.
* Keep this in sync with the redirects() block in next.config.mjs.
*/
export const REDIRECTED_BLOG_SLUGS = new Set<string>([
"qr-code-analytics",
"qr-code-restaurant-menu",
]);
export function isRedirectedSlug(slug: string): boolean {
return REDIRECTED_BLOG_SLUGS.has(slug);
}
export function getPublishedPosts(): BlogPost[] {
const currentDate = new Date();
return blogPosts.filter(p => {
if (!p.published) return false;
if (REDIRECTED_BLOG_SLUGS.has(p.slug)) return false;
const publishDate = p.datePublished ? new Date(p.datePublished) : new Date(p.date);
return publishDate <= currentDate;
});

View File

@@ -1,6 +1,7 @@
import axios from 'axios';
import dotenv from 'dotenv';
import { blogPosts } from '../lib/blog-data';
import { REDIRECTED_BLOG_SLUGS } from './content';
import { pillarMeta } from '../lib/pillar-data';
import { authors } from '../lib/author-data';
import { publishedUseCases } from '../lib/growth-pages';
@@ -73,7 +74,9 @@ export function getAllIndexableUrls(): string[] {
];
// Blog posts
const blogPages = blogPosts.map(post => `${baseUrl}/blog/${post.slug}`);
const blogPages = blogPosts
.filter(post => !REDIRECTED_BLOG_SLUGS.has(post.slug))
.map(post => `${baseUrl}/blog/${post.slug}`);
// Main pages (synced with sitemap.ts)
const mainPages = [