SEO blog post V2
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -77,6 +77,11 @@ meta-fix.js
|
|||||||
read-inbox.mjs
|
read-inbox.mjs
|
||||||
quora_antwort_statisch_dynamisch.txt
|
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
|
# Local developer-package workspaces and unreferenced generated media
|
||||||
/packages/
|
/packages/
|
||||||
/public/Events/
|
/public/Events/
|
||||||
|
|||||||
5569
package-lock.json
generated
5569
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,97 +1,99 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type { Metadata } from 'next';
|
import type { Metadata } from 'next';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import SeoJsonLd from '@/components/SeoJsonLd';
|
import SeoJsonLd from '@/components/SeoJsonLd';
|
||||||
import { websiteSchema, breadcrumbSchema } from '@/lib/schema';
|
import { websiteSchema, breadcrumbSchema } from '@/lib/schema';
|
||||||
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/Card';
|
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/Card';
|
||||||
import { Badge } from '@/components/ui/Badge';
|
import { Badge } from '@/components/ui/Badge';
|
||||||
import Breadcrumbs, { BreadcrumbItem } from '@/components/Breadcrumbs';
|
import Breadcrumbs, { BreadcrumbItem } from '@/components/Breadcrumbs';
|
||||||
import { blogPosts } from '@/lib/blog-data';
|
import { blogPosts } from '@/lib/blog-data';
|
||||||
|
import { REDIRECTED_BLOG_SLUGS } from "@/lib/content";
|
||||||
// Enable Incremental Static Regeneration (ISR)
|
|
||||||
// Revalidate every hour
|
// Enable Incremental Static Regeneration (ISR)
|
||||||
export const revalidate = 3600;
|
// Revalidate every hour
|
||||||
|
export const revalidate = 3600;
|
||||||
function truncateAtWord(text: string, maxLength: number): string {
|
|
||||||
if (text.length <= maxLength) return text;
|
function truncateAtWord(text: string, maxLength: number): string {
|
||||||
const truncated = text.slice(0, maxLength);
|
if (text.length <= maxLength) return text;
|
||||||
const lastSpace = truncated.lastIndexOf(' ');
|
const truncated = text.slice(0, maxLength);
|
||||||
return lastSpace > 0 ? truncated.slice(0, lastSpace) : truncated;
|
const lastSpace = truncated.lastIndexOf(' ');
|
||||||
}
|
return lastSpace > 0 ? truncated.slice(0, lastSpace) : truncated;
|
||||||
|
}
|
||||||
export async function generateMetadata(): Promise<Metadata> {
|
|
||||||
const title = truncateAtWord('QR Insights: Latest QR Strategies', 60);
|
export async function generateMetadata(): Promise<Metadata> {
|
||||||
const description = truncateAtWord(
|
const title = truncateAtWord('QR Insights: Latest QR Strategies', 60);
|
||||||
'Expert guides on QR code strategies, marketing campaigns, tracking analytics, and best practices for small businesses and enterprises.',
|
const description = truncateAtWord(
|
||||||
160
|
'Expert guides on QR code strategies, marketing campaigns, tracking analytics, and best practices for small businesses and enterprises.',
|
||||||
);
|
160
|
||||||
|
);
|
||||||
return {
|
|
||||||
title,
|
return {
|
||||||
description,
|
title,
|
||||||
alternates: {
|
description,
|
||||||
canonical: 'https://www.qrmaster.net/blog',
|
alternates: {
|
||||||
languages: {
|
canonical: 'https://www.qrmaster.net/blog',
|
||||||
'x-default': 'https://www.qrmaster.net/blog',
|
languages: {
|
||||||
en: 'https://www.qrmaster.net/blog',
|
'x-default': 'https://www.qrmaster.net/blog',
|
||||||
},
|
en: 'https://www.qrmaster.net/blog',
|
||||||
},
|
},
|
||||||
openGraph: {
|
},
|
||||||
title,
|
openGraph: {
|
||||||
description,
|
title,
|
||||||
url: 'https://www.qrmaster.net/blog',
|
description,
|
||||||
type: 'website',
|
url: 'https://www.qrmaster.net/blog',
|
||||||
images: ['/og-image.png'],
|
type: 'website',
|
||||||
},
|
images: ['/og-image.png'],
|
||||||
twitter: {
|
},
|
||||||
title,
|
twitter: {
|
||||||
description,
|
title,
|
||||||
},
|
description,
|
||||||
};
|
},
|
||||||
}
|
};
|
||||||
|
}
|
||||||
export default function BlogPage() {
|
|
||||||
const breadcrumbItems: BreadcrumbItem[] = [
|
export default function BlogPage() {
|
||||||
{ name: 'Home', url: '/' },
|
const breadcrumbItems: BreadcrumbItem[] = [
|
||||||
{ name: 'Blog', url: '/blog' },
|
{ name: 'Home', url: '/' },
|
||||||
];
|
{ name: 'Blog', url: '/blog' },
|
||||||
|
];
|
||||||
// Filter posts to only show those published in the past or today
|
|
||||||
// sort by date descending (newest first)
|
// Filter posts to only show those published in the past or today
|
||||||
const currentDate = new Date();
|
// sort by date descending (newest first)
|
||||||
|
const currentDate = new Date();
|
||||||
const publishedPosts = blogPosts
|
|
||||||
.filter(post => {
|
const publishedPosts = blogPosts
|
||||||
const publishDate = post.datePublished ? new Date(post.datePublished) : new Date(post.date);
|
.filter(post => {
|
||||||
return publishDate <= currentDate;
|
if (REDIRECTED_BLOG_SLUGS.has(post.slug)) return false;
|
||||||
})
|
const publishDate = post.datePublished ? new Date(post.datePublished) : new Date(post.date);
|
||||||
.sort((a, b) => {
|
return publishDate <= currentDate;
|
||||||
const dateA = a.datePublished ? new Date(a.datePublished) : new Date(a.date);
|
})
|
||||||
const dateB = b.datePublished ? new Date(b.datePublished) : new Date(b.date);
|
.sort((a, b) => {
|
||||||
return dateB.getTime() - dateA.getTime();
|
const dateA = a.datePublished ? new Date(a.datePublished) : new Date(a.date);
|
||||||
});
|
const dateB = b.datePublished ? new Date(b.datePublished) : new Date(b.date);
|
||||||
|
return dateB.getTime() - dateA.getTime();
|
||||||
return (
|
});
|
||||||
<>
|
|
||||||
<SeoJsonLd data={[websiteSchema(), breadcrumbSchema(breadcrumbItems)]} />
|
return (
|
||||||
<div className="py-20 bg-gradient-to-b from-gray-50 to-white">
|
<>
|
||||||
<div className="container mx-auto px-4">
|
<SeoJsonLd data={[websiteSchema(), breadcrumbSchema(breadcrumbItems)]} />
|
||||||
<Breadcrumbs items={breadcrumbItems} />
|
<div className="py-20 bg-gradient-to-b from-gray-50 to-white">
|
||||||
<div className="text-center mb-16">
|
<div className="container mx-auto px-4">
|
||||||
<h1 className="text-4xl lg:text-5xl font-bold text-gray-900 mb-6">
|
<Breadcrumbs items={breadcrumbItems} />
|
||||||
QR Code Insights
|
<div className="text-center mb-16">
|
||||||
</h1>
|
<h1 className="text-4xl lg:text-5xl font-bold text-gray-900 mb-6">
|
||||||
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
|
QR Code Insights
|
||||||
Expert guides on dynamic QR codes, campaign tracking, UTM analytics, and smart marketing use cases.
|
</h1>
|
||||||
Discover how-to tutorials and best practices for QR code analytics.
|
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
|
||||||
</p>
|
Expert guides on dynamic QR codes, campaign tracking, UTM analytics, and smart marketing use cases.
|
||||||
</div>
|
Discover how-to tutorials and best practices for QR code analytics.
|
||||||
|
</p>
|
||||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8 max-w-6xl mx-auto">
|
</div>
|
||||||
{publishedPosts.map((post) => (
|
|
||||||
<Link key={post.slug} href={`/blog/${post.slug}`}>
|
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8 max-w-6xl mx-auto">
|
||||||
<Card hover className="h-full overflow-hidden shadow-md hover:shadow-xl transition-all duration-300">
|
{publishedPosts.map((post) => (
|
||||||
|
<Link key={post.slug} href={`/blog/${post.slug}`}>
|
||||||
|
<Card hover className="h-full overflow-hidden shadow-md hover:shadow-xl transition-all duration-300">
|
||||||
<div className="relative h-56 overflow-hidden">
|
<div className="relative h-56 overflow-hidden">
|
||||||
<Image
|
<Image
|
||||||
src={post.image}
|
src={post.image}
|
||||||
@@ -102,26 +104,26 @@ export default function BlogPage() {
|
|||||||
className="w-full h-full object-cover transition-transform duration-500 hover:scale-110"
|
className="w-full h-full object-cover transition-transform duration-500 hover:scale-110"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<CardHeader className="pb-3">
|
<CardHeader className="pb-3">
|
||||||
<div className="flex items-center justify-between mb-3">
|
<div className="flex items-center justify-between mb-3">
|
||||||
<Badge variant="info">{post.category}</Badge>
|
<Badge variant="info">{post.category}</Badge>
|
||||||
<span className="text-sm text-gray-500 font-medium">{post.readTime} read</span>
|
<span className="text-sm text-gray-500 font-medium">{post.readTime} read</span>
|
||||||
</div>
|
</div>
|
||||||
<CardTitle className="text-xl leading-tight mb-3">{post.title}</CardTitle>
|
<CardTitle className="text-xl leading-tight mb-3">{post.title}</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="pt-0">
|
<CardContent className="pt-0">
|
||||||
<p className="text-gray-600 mb-4 leading-relaxed">{post.excerpt}</p>
|
<p className="text-gray-600 mb-4 leading-relaxed">{post.excerpt}</p>
|
||||||
<div className="flex items-center justify-between pt-4 border-t border-gray-100">
|
<div className="flex items-center justify-between pt-4 border-t border-gray-100">
|
||||||
<p className="text-sm text-gray-500">{post.date}</p>
|
<p className="text-sm text-gray-500">{post.date}</p>
|
||||||
<span className="text-primary-600 text-sm font-medium">Read more →</span>
|
<span className="text-primary-600 text-sm font-medium">Read more →</span>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,306 +1,308 @@
|
|||||||
import { MetadataRoute } from 'next';
|
import { MetadataRoute } from 'next';
|
||||||
import { blogPosts } from '../lib/blog-data';
|
import { blogPosts } from '../lib/blog-data';
|
||||||
import { pillarMeta } from '../lib/pillar-data';
|
import { REDIRECTED_BLOG_SLUGS } from '../lib/content';
|
||||||
import { authors } from '../lib/author-data';
|
import { pillarMeta } from '../lib/pillar-data';
|
||||||
import { industryPages } from '../lib/industry-pages';
|
import { authors } from '../lib/author-data';
|
||||||
import {
|
import { industryPages } from '../lib/industry-pages';
|
||||||
publishedComparisonPages,
|
import {
|
||||||
publishedGuidePages,
|
publishedComparisonPages,
|
||||||
} from '../lib/pseo-published-pages';
|
publishedGuidePages,
|
||||||
import { publishedUseCases } from '../lib/growth-pages';
|
} from '../lib/pseo-published-pages';
|
||||||
import { useCasePagesDe } from '../lib/growth-pages-de';
|
import { publishedUseCases } from '../lib/growth-pages';
|
||||||
|
import { useCasePagesDe } from '../lib/growth-pages-de';
|
||||||
export default function sitemap(): MetadataRoute.Sitemap {
|
|
||||||
const baseUrl = 'https://www.qrmaster.net';
|
export default function sitemap(): MetadataRoute.Sitemap {
|
||||||
|
const baseUrl = 'https://www.qrmaster.net';
|
||||||
// All free tool slugs
|
|
||||||
const freeTools = [
|
// All free tool slugs
|
||||||
'url-qr-code',
|
const freeTools = [
|
||||||
'vcard-qr-code',
|
'url-qr-code',
|
||||||
'text-qr-code',
|
'vcard-qr-code',
|
||||||
'email-qr-code',
|
'text-qr-code',
|
||||||
'sms-qr-code',
|
'email-qr-code',
|
||||||
'wifi-qr-code',
|
'sms-qr-code',
|
||||||
'crypto-qr-code',
|
'wifi-qr-code',
|
||||||
'event-qr-code',
|
'crypto-qr-code',
|
||||||
'facebook-qr-code',
|
'event-qr-code',
|
||||||
'instagram-qr-code',
|
'facebook-qr-code',
|
||||||
'twitter-qr-code',
|
'instagram-qr-code',
|
||||||
'youtube-qr-code',
|
'twitter-qr-code',
|
||||||
'whatsapp-qr-code',
|
'youtube-qr-code',
|
||||||
'tiktok-qr-code',
|
'whatsapp-qr-code',
|
||||||
'geolocation-qr-code',
|
'tiktok-qr-code',
|
||||||
'call-qr-code-generator',
|
'geolocation-qr-code',
|
||||||
'paypal-qr-code',
|
'call-qr-code-generator',
|
||||||
'zoom-qr-code',
|
'paypal-qr-code',
|
||||||
'teams-qr-code',
|
'zoom-qr-code',
|
||||||
'google-review-qr-code',
|
'teams-qr-code',
|
||||||
'barcode-generator',
|
'google-review-qr-code',
|
||||||
];
|
'barcode-generator',
|
||||||
|
];
|
||||||
// All blog posts
|
|
||||||
// Filter out future posts so Google doesn't see them
|
// All blog posts
|
||||||
const blogPages = blogPosts
|
// Filter out future posts so Google doesn't see them
|
||||||
.filter((post) => {
|
const blogPages = blogPosts
|
||||||
const publishDate = post.datePublished
|
.filter((post) => {
|
||||||
? new Date(post.datePublished)
|
if (REDIRECTED_BLOG_SLUGS.has(post.slug)) return false;
|
||||||
: new Date(post.date);
|
const publishDate = post.datePublished
|
||||||
return publishDate <= new Date();
|
? new Date(post.datePublished)
|
||||||
})
|
: new Date(post.date);
|
||||||
.map((post) => ({
|
return publishDate <= new Date();
|
||||||
url: `${baseUrl}/blog/${post.slug}`,
|
})
|
||||||
// Use updatedAt if available, otherwise dateModified or datePublished
|
.map((post) => ({
|
||||||
lastModified: post.updatedAt
|
url: `${baseUrl}/blog/${post.slug}`,
|
||||||
? new Date(post.updatedAt)
|
// Use updatedAt if available, otherwise dateModified or datePublished
|
||||||
: post.dateModified
|
lastModified: post.updatedAt
|
||||||
? new Date(post.dateModified)
|
? new Date(post.updatedAt)
|
||||||
: new Date(),
|
: post.dateModified
|
||||||
changeFrequency: 'monthly' as const,
|
? new Date(post.dateModified)
|
||||||
priority: 0.8,
|
: new Date(),
|
||||||
}));
|
changeFrequency: 'monthly' as const,
|
||||||
|
priority: 0.8,
|
||||||
const highPriorityTools: Record<string, number> = {
|
}));
|
||||||
'barcode-generator': 0.95,
|
|
||||||
'google-review-qr-code': 0.9,
|
const highPriorityTools: Record<string, number> = {
|
||||||
};
|
'barcode-generator': 0.95,
|
||||||
|
'google-review-qr-code': 0.9,
|
||||||
const toolLastModified: Record<string, Date> = {
|
};
|
||||||
'barcode-generator': new Date('2026-05-10'),
|
|
||||||
'vcard-qr-code': new Date('2026-04-27'),
|
const toolLastModified: Record<string, Date> = {
|
||||||
'instagram-qr-code': new Date('2026-04-27'),
|
'barcode-generator': new Date('2026-05-10'),
|
||||||
'wifi-qr-code': new Date('2026-04-27'),
|
'vcard-qr-code': new Date('2026-04-27'),
|
||||||
};
|
'instagram-qr-code': new Date('2026-04-27'),
|
||||||
|
'wifi-qr-code': new Date('2026-04-27'),
|
||||||
const toolPages = freeTools.map((slug) => ({
|
};
|
||||||
url: `${baseUrl}/tools/${slug}`,
|
|
||||||
lastModified: toolLastModified[slug] ?? new Date('2026-01-01'),
|
const toolPages = freeTools.map((slug) => ({
|
||||||
changeFrequency:
|
url: `${baseUrl}/tools/${slug}`,
|
||||||
slug === 'barcode-generator' ? ('weekly' as const) : ('monthly' as const),
|
lastModified: toolLastModified[slug] ?? new Date('2026-01-01'),
|
||||||
priority: highPriorityTools[slug] ?? 0.8,
|
changeFrequency:
|
||||||
}));
|
slug === 'barcode-generator' ? ('weekly' as const) : ('monthly' as const),
|
||||||
|
priority: highPriorityTools[slug] ?? 0.8,
|
||||||
// Learn hub and pillar pages
|
}));
|
||||||
const learnPages = [
|
|
||||||
{
|
// Learn hub and pillar pages
|
||||||
url: `${baseUrl}/learn`,
|
const learnPages = [
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'weekly' as const,
|
url: `${baseUrl}/learn`,
|
||||||
priority: 0.9,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'weekly' as const,
|
||||||
...pillarMeta.map((pillar) => ({
|
priority: 0.9,
|
||||||
url: `${baseUrl}/learn/${pillar.key}`,
|
},
|
||||||
lastModified: new Date(),
|
...pillarMeta.map((pillar) => ({
|
||||||
changeFrequency: 'monthly' as const,
|
url: `${baseUrl}/learn/${pillar.key}`,
|
||||||
priority: 0.8,
|
lastModified: new Date(),
|
||||||
})),
|
changeFrequency: 'monthly' as const,
|
||||||
];
|
priority: 0.8,
|
||||||
|
})),
|
||||||
const industryUrls = industryPages.map((industry) => ({
|
];
|
||||||
url: `${baseUrl}/qr-code-for/${industry.slug}`,
|
|
||||||
lastModified: new Date(),
|
const industryUrls = industryPages.map((industry) => ({
|
||||||
changeFrequency: 'monthly' as const,
|
url: `${baseUrl}/qr-code-for/${industry.slug}`,
|
||||||
priority: 0.85,
|
lastModified: new Date(),
|
||||||
}));
|
changeFrequency: 'monthly' as const,
|
||||||
|
priority: 0.85,
|
||||||
const growthUseCasePages = [
|
}));
|
||||||
{
|
|
||||||
url: `${baseUrl}/use-cases`,
|
const growthUseCasePages = [
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'weekly' as const,
|
url: `${baseUrl}/use-cases`,
|
||||||
priority: 0.9,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'weekly' as const,
|
||||||
{
|
priority: 0.9,
|
||||||
url: `${baseUrl}/qr-code-for`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'weekly' as const,
|
url: `${baseUrl}/qr-code-for`,
|
||||||
priority: 0.9,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'weekly' as const,
|
||||||
...publishedUseCases.map((useCase) => ({
|
priority: 0.9,
|
||||||
url: `${baseUrl}${useCase.href}`,
|
},
|
||||||
lastModified: new Date(),
|
...publishedUseCases.map((useCase) => ({
|
||||||
changeFrequency: 'monthly' as const,
|
url: `${baseUrl}${useCase.href}`,
|
||||||
priority: 0.8,
|
lastModified: new Date(),
|
||||||
})),
|
changeFrequency: 'monthly' as const,
|
||||||
// German pages under /de
|
priority: 0.8,
|
||||||
{
|
})),
|
||||||
url: `${baseUrl}/de/preise`,
|
// German pages under /de
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'monthly' as const,
|
url: `${baseUrl}/de/preise`,
|
||||||
priority: 0.8,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'monthly' as const,
|
||||||
...Object.values(useCasePagesDe).map((useCase) => ({
|
priority: 0.8,
|
||||||
url: `${baseUrl}${useCase.href}`,
|
},
|
||||||
lastModified: new Date(),
|
...Object.values(useCasePagesDe).map((useCase) => ({
|
||||||
changeFrequency: 'monthly' as const,
|
url: `${baseUrl}${useCase.href}`,
|
||||||
priority: 0.8,
|
lastModified: new Date(),
|
||||||
})),
|
changeFrequency: 'monthly' as const,
|
||||||
{
|
priority: 0.8,
|
||||||
url: `${baseUrl}/qr-code-for-marketing-campaigns`,
|
})),
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'monthly' as const,
|
url: `${baseUrl}/qr-code-for-marketing-campaigns`,
|
||||||
priority: 0.85,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'monthly' as const,
|
||||||
];
|
priority: 0.85,
|
||||||
|
},
|
||||||
const publishedPseoPages = [
|
];
|
||||||
...publishedComparisonPages.map((page) => ({
|
|
||||||
url: `${baseUrl}${page.canonicalPath}`,
|
const publishedPseoPages = [
|
||||||
lastModified: new Date('2026-06-22'),
|
...publishedComparisonPages.map((page) => ({
|
||||||
changeFrequency: 'monthly' as const,
|
url: `${baseUrl}${page.canonicalPath}`,
|
||||||
priority: page.intentStage === 'bottom' ? 0.88 : 0.84,
|
lastModified: new Date('2026-06-22'),
|
||||||
})),
|
changeFrequency: 'monthly' as const,
|
||||||
...publishedGuidePages.map((page) => ({
|
priority: page.intentStage === 'bottom' ? 0.88 : 0.84,
|
||||||
url: `${baseUrl}${page.canonicalPath}`,
|
})),
|
||||||
lastModified: new Date('2026-06-22'),
|
...publishedGuidePages.map((page) => ({
|
||||||
changeFrequency: 'monthly' as const,
|
url: `${baseUrl}${page.canonicalPath}`,
|
||||||
priority: 0.82,
|
lastModified: new Date('2026-06-22'),
|
||||||
})),
|
changeFrequency: 'monthly' as const,
|
||||||
];
|
priority: 0.82,
|
||||||
|
})),
|
||||||
// Author pages
|
];
|
||||||
const authorPages = authors.map((author) => ({
|
|
||||||
url: `${baseUrl}/authors/${author.slug}`,
|
// Author pages
|
||||||
lastModified: new Date(),
|
const authorPages = authors.map((author) => ({
|
||||||
changeFrequency: 'monthly' as const,
|
url: `${baseUrl}/authors/${author.slug}`,
|
||||||
priority: 0.7,
|
lastModified: new Date(),
|
||||||
}));
|
changeFrequency: 'monthly' as const,
|
||||||
|
priority: 0.7,
|
||||||
return [
|
}));
|
||||||
{
|
|
||||||
url: baseUrl,
|
return [
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'weekly',
|
url: baseUrl,
|
||||||
priority: 1.0,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'weekly',
|
||||||
{
|
priority: 1.0,
|
||||||
url: `${baseUrl}/newsletter`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'monthly',
|
url: `${baseUrl}/newsletter`,
|
||||||
priority: 0.7,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'monthly',
|
||||||
{
|
priority: 0.7,
|
||||||
url: `${baseUrl}/restaurants`,
|
},
|
||||||
lastModified: new Date('2026-04-30'),
|
{
|
||||||
changeFrequency: 'weekly',
|
url: `${baseUrl}/restaurants`,
|
||||||
priority: 0.9,
|
lastModified: new Date('2026-04-30'),
|
||||||
},
|
changeFrequency: 'weekly',
|
||||||
{
|
priority: 0.9,
|
||||||
url: `${baseUrl}/qr-code-erstellen`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'weekly',
|
url: `${baseUrl}/qr-code-erstellen`,
|
||||||
priority: 1.0,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'weekly',
|
||||||
{
|
priority: 1.0,
|
||||||
url: `${baseUrl}/qr-code-tracking`,
|
},
|
||||||
lastModified: new Date('2026-05-10'),
|
{
|
||||||
changeFrequency: 'monthly',
|
url: `${baseUrl}/qr-code-tracking`,
|
||||||
priority: 0.9,
|
lastModified: new Date('2026-05-10'),
|
||||||
},
|
changeFrequency: 'monthly',
|
||||||
{
|
priority: 0.9,
|
||||||
url: `${baseUrl}/qr-code-analytics`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'monthly',
|
url: `${baseUrl}/qr-code-analytics`,
|
||||||
priority: 0.9,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'monthly',
|
||||||
{
|
priority: 0.9,
|
||||||
url: `${baseUrl}/reprint-calculator`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'monthly',
|
url: `${baseUrl}/reprint-calculator`,
|
||||||
priority: 0.9,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'monthly',
|
||||||
{
|
priority: 0.9,
|
||||||
url: `${baseUrl}/dynamic-qr-code-generator`,
|
},
|
||||||
lastModified: new Date('2026-05-10'),
|
{
|
||||||
changeFrequency: 'weekly',
|
url: `${baseUrl}/dynamic-qr-code-generator`,
|
||||||
priority: 0.95,
|
lastModified: new Date('2026-05-10'),
|
||||||
},
|
changeFrequency: 'weekly',
|
||||||
{
|
priority: 0.95,
|
||||||
url: `${baseUrl}/dynamic-barcode-generator`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'monthly',
|
url: `${baseUrl}/dynamic-barcode-generator`,
|
||||||
priority: 0.9,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'monthly',
|
||||||
{
|
priority: 0.9,
|
||||||
url: `${baseUrl}/bulk-qr-code-generator`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'monthly',
|
url: `${baseUrl}/bulk-qr-code-generator`,
|
||||||
priority: 0.9,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'monthly',
|
||||||
{
|
priority: 0.9,
|
||||||
url: `${baseUrl}/custom-qr-code-generator`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'weekly',
|
url: `${baseUrl}/custom-qr-code-generator`,
|
||||||
priority: 0.9,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'weekly',
|
||||||
|
priority: 0.9,
|
||||||
{
|
},
|
||||||
url: `${baseUrl}/pricing`,
|
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'monthly',
|
url: `${baseUrl}/pricing`,
|
||||||
priority: 0.8,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'monthly',
|
||||||
{
|
priority: 0.8,
|
||||||
url: `${baseUrl}/tools`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'monthly',
|
url: `${baseUrl}/tools`,
|
||||||
priority: 0.9,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'monthly',
|
||||||
{
|
priority: 0.9,
|
||||||
url: `${baseUrl}/features`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'monthly',
|
url: `${baseUrl}/features`,
|
||||||
priority: 0.8,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'monthly',
|
||||||
{
|
priority: 0.8,
|
||||||
url: `${baseUrl}/faq`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'monthly',
|
url: `${baseUrl}/faq`,
|
||||||
priority: 0.7,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'monthly',
|
||||||
{
|
priority: 0.7,
|
||||||
url: `${baseUrl}/blog`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'weekly',
|
url: `${baseUrl}/blog`,
|
||||||
priority: 0.8,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'weekly',
|
||||||
|
priority: 0.8,
|
||||||
{
|
},
|
||||||
url: `${baseUrl}/privacy`,
|
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'yearly',
|
url: `${baseUrl}/privacy`,
|
||||||
priority: 0.4,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'yearly',
|
||||||
{
|
priority: 0.4,
|
||||||
url: `${baseUrl}/contact`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'yearly',
|
url: `${baseUrl}/contact`,
|
||||||
priority: 0.5,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'yearly',
|
||||||
{
|
priority: 0.5,
|
||||||
url: `${baseUrl}/about`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'yearly',
|
url: `${baseUrl}/about`,
|
||||||
priority: 0.6,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'yearly',
|
||||||
{
|
priority: 0.6,
|
||||||
url: `${baseUrl}/press`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'monthly',
|
url: `${baseUrl}/press`,
|
||||||
priority: 0.7,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'monthly',
|
||||||
{
|
priority: 0.7,
|
||||||
url: `${baseUrl}/testimonials`,
|
},
|
||||||
lastModified: new Date(),
|
{
|
||||||
changeFrequency: 'monthly',
|
url: `${baseUrl}/testimonials`,
|
||||||
priority: 0.7,
|
lastModified: new Date(),
|
||||||
},
|
changeFrequency: 'monthly',
|
||||||
|
priority: 0.7,
|
||||||
...toolPages,
|
},
|
||||||
...blogPages,
|
|
||||||
...learnPages,
|
...toolPages,
|
||||||
...growthUseCasePages,
|
...blogPages,
|
||||||
...publishedPseoPages,
|
...learnPages,
|
||||||
...industryUrls,
|
...growthUseCasePages,
|
||||||
...authorPages,
|
...publishedPseoPages,
|
||||||
];
|
...industryUrls,
|
||||||
}
|
...authorPages,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|||||||
9039
src/lib/blog-data.ts
9039
src/lib/blog-data.ts
File diff suppressed because it is too large
Load Diff
@@ -1,59 +1,76 @@
|
|||||||
import { blogPosts } from "./blog-data";
|
import { blogPosts } from "./blog-data";
|
||||||
import { authors } from "./author-data";
|
import { authors } from "./author-data";
|
||||||
import type { BlogPost, PillarKey, AuthorProfile } from "./types";
|
import type { BlogPost, PillarKey, AuthorProfile } from "./types";
|
||||||
|
|
||||||
export function getPublishedPosts(): BlogPost[] {
|
/**
|
||||||
const currentDate = new Date();
|
* Blog slugs that are 301-redirected in next.config.mjs.
|
||||||
return blogPosts.filter(p => {
|
* They must not appear in the blog index, the learn pillars, the sitemap
|
||||||
if (!p.published) return false;
|
* or IndexNow submissions - linking to a redirect source wastes crawl budget
|
||||||
const publishDate = p.datePublished ? new Date(p.datePublished) : new Date(p.date);
|
* and passes link equity through an unnecessary hop.
|
||||||
return publishDate <= currentDate;
|
* Keep this in sync with the redirects() block in next.config.mjs.
|
||||||
});
|
*/
|
||||||
}
|
export const REDIRECTED_BLOG_SLUGS = new Set<string>([
|
||||||
|
"qr-code-analytics",
|
||||||
export function getPostBySlug(slug: string): BlogPost | undefined {
|
"qr-code-restaurant-menu",
|
||||||
return blogPosts.find(p => p.slug === slug);
|
]);
|
||||||
}
|
|
||||||
|
export function isRedirectedSlug(slug: string): boolean {
|
||||||
export function getPublishedPostBySlug(slug: string): BlogPost | undefined {
|
return REDIRECTED_BLOG_SLUGS.has(slug);
|
||||||
const p = getPostBySlug(slug);
|
}
|
||||||
if (!p?.published) return undefined;
|
|
||||||
|
export function getPublishedPosts(): BlogPost[] {
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
const publishDate = p.datePublished ? new Date(p.datePublished) : new Date(p.date);
|
return blogPosts.filter(p => {
|
||||||
return publishDate <= currentDate ? p : undefined;
|
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);
|
||||||
export function getPostsByPillar(pillar: PillarKey): BlogPost[] {
|
return publishDate <= currentDate;
|
||||||
return getPublishedPosts()
|
});
|
||||||
.filter(p => p.pillar === pillar)
|
}
|
||||||
.sort((a, b) => (new Date(a.datePublished).getTime() < new Date(b.datePublished).getTime() ? 1 : -1));
|
|
||||||
}
|
export function getPostBySlug(slug: string): BlogPost | undefined {
|
||||||
|
return blogPosts.find(p => p.slug === slug);
|
||||||
export function getAuthorBySlug(slug: string): AuthorProfile | undefined {
|
}
|
||||||
return authors.find(a => a.slug === slug);
|
|
||||||
}
|
export function getPublishedPostBySlug(slug: string): BlogPost | undefined {
|
||||||
|
const p = getPostBySlug(slug);
|
||||||
export function getPostsByAuthor(slug: string): BlogPost[] {
|
if (!p?.published) return undefined;
|
||||||
return getPublishedPosts()
|
|
||||||
.filter(p => p.authorSlug === slug)
|
const currentDate = new Date();
|
||||||
.sort((a, b) => (new Date(a.datePublished).getTime() < new Date(b.datePublished).getTime() ? 1 : -1));
|
const publishDate = p.datePublished ? new Date(p.datePublished) : new Date(p.date);
|
||||||
}
|
return publishDate <= currentDate ? p : undefined;
|
||||||
|
}
|
||||||
export function getRelatedPosts(post: BlogPost, limit = 4): BlogPost[] {
|
|
||||||
const published = getPublishedPosts();
|
export function getPostsByPillar(pillar: PillarKey): BlogPost[] {
|
||||||
|
return getPublishedPosts()
|
||||||
// explicit relatedSlugs first
|
.filter(p => p.pillar === pillar)
|
||||||
const explicit = (post.relatedSlugs ?? [])
|
.sort((a, b) => (new Date(a.datePublished).getTime() < new Date(b.datePublished).getTime() ? 1 : -1));
|
||||||
.map(s => published.find(p => p.slug === s))
|
}
|
||||||
.filter((p): p is BlogPost => !!p);
|
|
||||||
|
export function getAuthorBySlug(slug: string): AuthorProfile | undefined {
|
||||||
if (explicit.length >= limit) return explicit.slice(0, limit);
|
return authors.find(a => a.slug === slug);
|
||||||
|
}
|
||||||
// fallback: same pillar, not itself, newest
|
|
||||||
const fallback = published
|
export function getPostsByAuthor(slug: string): BlogPost[] {
|
||||||
.filter(p => p.slug !== post.slug && p.pillar === post.pillar)
|
return getPublishedPosts()
|
||||||
.slice(0, limit - explicit.length);
|
.filter(p => p.authorSlug === slug)
|
||||||
|
.sort((a, b) => (new Date(a.datePublished).getTime() < new Date(b.datePublished).getTime() ? 1 : -1));
|
||||||
return [...explicit, ...fallback];
|
}
|
||||||
}
|
|
||||||
|
export function getRelatedPosts(post: BlogPost, limit = 4): BlogPost[] {
|
||||||
|
const published = getPublishedPosts();
|
||||||
|
|
||||||
|
// explicit relatedSlugs first
|
||||||
|
const explicit = (post.relatedSlugs ?? [])
|
||||||
|
.map(s => published.find(p => p.slug === s))
|
||||||
|
.filter((p): p is BlogPost => !!p);
|
||||||
|
|
||||||
|
if (explicit.length >= limit) return explicit.slice(0, limit);
|
||||||
|
|
||||||
|
// fallback: same pillar, not itself, newest
|
||||||
|
const fallback = published
|
||||||
|
.filter(p => p.slug !== post.slug && p.pillar === post.pillar)
|
||||||
|
.slice(0, limit - explicit.length);
|
||||||
|
|
||||||
|
return [...explicit, ...fallback];
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,166 +1,169 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import { blogPosts } from '../lib/blog-data';
|
import { blogPosts } from '../lib/blog-data';
|
||||||
import { pillarMeta } from '../lib/pillar-data';
|
import { REDIRECTED_BLOG_SLUGS } from './content';
|
||||||
import { authors } from '../lib/author-data';
|
import { pillarMeta } from '../lib/pillar-data';
|
||||||
import { publishedUseCases } from '../lib/growth-pages';
|
import { authors } from '../lib/author-data';
|
||||||
import { useCasePagesDe } from '../lib/growth-pages-de';
|
import { publishedUseCases } from '../lib/growth-pages';
|
||||||
import { industryPages } from '../lib/industry-pages';
|
import { useCasePagesDe } from '../lib/growth-pages-de';
|
||||||
import { publishedComparisonPages, publishedGuidePages } from '../lib/pseo-published-pages';
|
import { industryPages } from '../lib/industry-pages';
|
||||||
|
import { publishedComparisonPages, publishedGuidePages } from '../lib/pseo-published-pages';
|
||||||
dotenv.config();
|
|
||||||
|
dotenv.config();
|
||||||
const INDEXNOW_ENDPOINT = 'https://api.indexnow.org/indexnow';
|
|
||||||
const HOST = 'www.qrmaster.net';
|
const INDEXNOW_ENDPOINT = 'https://api.indexnow.org/indexnow';
|
||||||
// You need to generate a key from https://www.bing.com/indexnow and place it in your public folder
|
const HOST = 'www.qrmaster.net';
|
||||||
// Key must be set in .env as INDEXNOW_KEY
|
// You need to generate a key from https://www.bing.com/indexnow and place it in your public folder
|
||||||
const KEY = process.env.INDEXNOW_KEY!;
|
// Key must be set in .env as INDEXNOW_KEY
|
||||||
const KEY_LOCATION = `https://${HOST}/${KEY}.txt`;
|
const KEY = process.env.INDEXNOW_KEY!;
|
||||||
|
const KEY_LOCATION = `https://${HOST}/${KEY}.txt`;
|
||||||
export async function submitToIndexNow(urls: string[]) {
|
|
||||||
try {
|
export async function submitToIndexNow(urls: string[]) {
|
||||||
const payload = {
|
try {
|
||||||
host: HOST,
|
const payload = {
|
||||||
key: KEY,
|
host: HOST,
|
||||||
keyLocation: KEY_LOCATION,
|
key: KEY,
|
||||||
urlList: urls,
|
keyLocation: KEY_LOCATION,
|
||||||
};
|
urlList: urls,
|
||||||
|
};
|
||||||
console.log(`Submitting ${urls.length} URLs to IndexNow...`);
|
|
||||||
const response = await axios.post(INDEXNOW_ENDPOINT, payload, {
|
console.log(`Submitting ${urls.length} URLs to IndexNow...`);
|
||||||
headers: {
|
const response = await axios.post(INDEXNOW_ENDPOINT, payload, {
|
||||||
'Content-Type': 'application/json',
|
headers: {
|
||||||
},
|
'Content-Type': 'application/json',
|
||||||
});
|
},
|
||||||
|
});
|
||||||
if (response.status === 200 || response.status === 202) {
|
|
||||||
console.log('✅ Successfully submitted URLs to IndexNow.');
|
if (response.status === 200 || response.status === 202) {
|
||||||
} else {
|
console.log('✅ Successfully submitted URLs to IndexNow.');
|
||||||
console.error(`⚠️ IndexNow submission returned status: ${response.status}`);
|
} else {
|
||||||
}
|
console.error(`⚠️ IndexNow submission returned status: ${response.status}`);
|
||||||
} catch (error) {
|
}
|
||||||
if (axios.isAxiosError(error)) {
|
} catch (error) {
|
||||||
console.error('❌ Error submitting to IndexNow:', error.message);
|
if (axios.isAxiosError(error)) {
|
||||||
console.error('Response data:', error.response?.data);
|
console.error('❌ Error submitting to IndexNow:', error.message);
|
||||||
} else {
|
console.error('Response data:', error.response?.data);
|
||||||
console.error('❌ Unknown error submitting to IndexNow:', error);
|
} else {
|
||||||
}
|
console.error('❌ Unknown error submitting to IndexNow:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Function to gather all indexable URLs
|
|
||||||
export function getAllIndexableUrls(): string[] {
|
// Function to gather all indexable URLs
|
||||||
const baseUrl = `https://${HOST}`;
|
export function getAllIndexableUrls(): string[] {
|
||||||
|
const baseUrl = `https://${HOST}`;
|
||||||
// Free tools
|
|
||||||
const freeTools = [
|
// Free tools
|
||||||
'barcode-generator', // Added as per request
|
const freeTools = [
|
||||||
'url-qr-code', 'vcard-qr-code', 'text-qr-code', 'email-qr-code', 'sms-qr-code',
|
'barcode-generator', // Added as per request
|
||||||
'wifi-qr-code', 'crypto-qr-code', 'event-qr-code', 'facebook-qr-code',
|
'url-qr-code', 'vcard-qr-code', 'text-qr-code', 'email-qr-code', 'sms-qr-code',
|
||||||
'instagram-qr-code', 'twitter-qr-code', 'youtube-qr-code', 'whatsapp-qr-code',
|
'wifi-qr-code', 'crypto-qr-code', 'event-qr-code', 'facebook-qr-code',
|
||||||
'tiktok-qr-code', 'geolocation-qr-code', 'call-qr-code-generator', 'paypal-qr-code',
|
'instagram-qr-code', 'twitter-qr-code', 'youtube-qr-code', 'whatsapp-qr-code',
|
||||||
'zoom-qr-code', 'teams-qr-code', 'google-review-qr-code',
|
'tiktok-qr-code', 'geolocation-qr-code', 'call-qr-code-generator', 'paypal-qr-code',
|
||||||
].map(slug => `${baseUrl}/tools/${slug}`);
|
'zoom-qr-code', 'teams-qr-code', 'google-review-qr-code',
|
||||||
|
].map(slug => `${baseUrl}/tools/${slug}`);
|
||||||
// Use-case pages (English) and their German twins under /de
|
|
||||||
const useCasePages = [
|
// Use-case pages (English) and their German twins under /de
|
||||||
`${baseUrl}/use-cases`,
|
const useCasePages = [
|
||||||
...publishedUseCases.map(uc => `${baseUrl}${uc.href}`),
|
`${baseUrl}/use-cases`,
|
||||||
];
|
...publishedUseCases.map(uc => `${baseUrl}${uc.href}`),
|
||||||
const germanPages = [
|
];
|
||||||
`${baseUrl}/de/preise`,
|
const germanPages = [
|
||||||
...Object.values(useCasePagesDe).map(uc => `${baseUrl}${uc.href}`),
|
`${baseUrl}/de/preise`,
|
||||||
];
|
...Object.values(useCasePagesDe).map(uc => `${baseUrl}${uc.href}`),
|
||||||
|
];
|
||||||
// Blog posts
|
|
||||||
const blogPages = blogPosts.map(post => `${baseUrl}/blog/${post.slug}`);
|
// Blog posts
|
||||||
|
const blogPages = blogPosts
|
||||||
// Main pages (synced with sitemap.ts)
|
.filter(post => !REDIRECTED_BLOG_SLUGS.has(post.slug))
|
||||||
const mainPages = [
|
.map(post => `${baseUrl}/blog/${post.slug}`);
|
||||||
baseUrl,
|
|
||||||
`${baseUrl}/about`,
|
// Main pages (synced with sitemap.ts)
|
||||||
`${baseUrl}/contact`,
|
const mainPages = [
|
||||||
`${baseUrl}/press`,
|
baseUrl,
|
||||||
`${baseUrl}/testimonials`,
|
`${baseUrl}/about`,
|
||||||
`${baseUrl}/qr-code-erstellen`,
|
`${baseUrl}/contact`,
|
||||||
`${baseUrl}/qr-code-tracking`,
|
`${baseUrl}/press`,
|
||||||
`${baseUrl}/reprint-calculator`,
|
`${baseUrl}/testimonials`,
|
||||||
`${baseUrl}/dynamic-qr-code-generator`,
|
`${baseUrl}/qr-code-erstellen`,
|
||||||
`${baseUrl}/dynamic-barcode-generator`,
|
`${baseUrl}/qr-code-tracking`,
|
||||||
`${baseUrl}/bulk-qr-code-generator`,
|
`${baseUrl}/reprint-calculator`,
|
||||||
`${baseUrl}/custom-qr-code-generator`,
|
`${baseUrl}/dynamic-qr-code-generator`,
|
||||||
`${baseUrl}/manage-qr-codes`,
|
`${baseUrl}/dynamic-barcode-generator`,
|
||||||
`${baseUrl}/pricing`,
|
`${baseUrl}/bulk-qr-code-generator`,
|
||||||
`${baseUrl}/tools`,
|
`${baseUrl}/custom-qr-code-generator`,
|
||||||
`${baseUrl}/features`,
|
`${baseUrl}/manage-qr-codes`,
|
||||||
`${baseUrl}/faq`,
|
`${baseUrl}/pricing`,
|
||||||
`${baseUrl}/blog`,
|
`${baseUrl}/tools`,
|
||||||
`${baseUrl}/privacy`,
|
`${baseUrl}/features`,
|
||||||
`${baseUrl}/newsletter`,
|
`${baseUrl}/faq`,
|
||||||
`${baseUrl}/cookie-policy`,
|
`${baseUrl}/blog`,
|
||||||
`${baseUrl}/terms`,
|
`${baseUrl}/privacy`,
|
||||||
`${baseUrl}/restaurants`,
|
`${baseUrl}/newsletter`,
|
||||||
`${baseUrl}/qr-code-analytics`,
|
`${baseUrl}/cookie-policy`,
|
||||||
`${baseUrl}/qr-code-print-size-guide`,
|
`${baseUrl}/terms`,
|
||||||
];
|
`${baseUrl}/restaurants`,
|
||||||
|
`${baseUrl}/qr-code-analytics`,
|
||||||
// Alternatives & comparison hub pages
|
`${baseUrl}/qr-code-print-size-guide`,
|
||||||
const alternativesPages = [
|
];
|
||||||
`${baseUrl}/alternatives`,
|
|
||||||
`${baseUrl}/alternatives/beaconstac`,
|
// Alternatives & comparison hub pages
|
||||||
`${baseUrl}/alternatives/bitly`,
|
const alternativesPages = [
|
||||||
`${baseUrl}/alternatives/flowcode`,
|
`${baseUrl}/alternatives`,
|
||||||
`${baseUrl}/alternatives/qr-code-generator`,
|
`${baseUrl}/alternatives/beaconstac`,
|
||||||
`${baseUrl}/vs`,
|
`${baseUrl}/alternatives/bitly`,
|
||||||
`${baseUrl}/vs/beaconstac`,
|
`${baseUrl}/alternatives/flowcode`,
|
||||||
];
|
`${baseUrl}/alternatives/qr-code-generator`,
|
||||||
|
`${baseUrl}/vs`,
|
||||||
// pSEO comparison & guide pages (published subset)
|
`${baseUrl}/vs/beaconstac`,
|
||||||
const pseoPages = [
|
];
|
||||||
...publishedComparisonPages.map(page => `${baseUrl}${page.canonicalPath}`),
|
|
||||||
...publishedGuidePages.map(page => `${baseUrl}${page.canonicalPath}`),
|
// pSEO comparison & guide pages (published subset)
|
||||||
];
|
const pseoPages = [
|
||||||
|
...publishedComparisonPages.map(page => `${baseUrl}${page.canonicalPath}`),
|
||||||
// Learn hub pillars (the /guide/* URLs these replaced are 301'd in next.config.mjs
|
...publishedGuidePages.map(page => `${baseUrl}${page.canonicalPath}`),
|
||||||
// and must never be submitted to IndexNow - see redirects() there)
|
];
|
||||||
const guidePages = [
|
|
||||||
`${baseUrl}/learn/developer`,
|
// Learn hub pillars (the /guide/* URLs these replaced are 301'd in next.config.mjs
|
||||||
`${baseUrl}/learn/basics`,
|
// and must never be submitted to IndexNow - see redirects() there)
|
||||||
`${baseUrl}/learn/tracking`,
|
const guidePages = [
|
||||||
];
|
`${baseUrl}/learn/developer`,
|
||||||
|
`${baseUrl}/learn/basics`,
|
||||||
// Industry landing pages
|
`${baseUrl}/learn/tracking`,
|
||||||
const industryHubPages = [
|
];
|
||||||
`${baseUrl}/qr-code-for`,
|
|
||||||
...industryPages.map(industry => `${baseUrl}/qr-code-for/${industry.slug}`),
|
// Industry landing pages
|
||||||
];
|
const industryHubPages = [
|
||||||
|
`${baseUrl}/qr-code-for`,
|
||||||
// Learn hub and pillar pages
|
...industryPages.map(industry => `${baseUrl}/qr-code-for/${industry.slug}`),
|
||||||
const learnPages = [
|
];
|
||||||
`${baseUrl}/learn`,
|
|
||||||
...pillarMeta.map(pillar => `${baseUrl}/learn/${pillar.key}`)
|
// Learn hub and pillar pages
|
||||||
];
|
const learnPages = [
|
||||||
|
`${baseUrl}/learn`,
|
||||||
// Author pages
|
...pillarMeta.map(pillar => `${baseUrl}/learn/${pillar.key}`)
|
||||||
const authorPages = authors.map(author => `${baseUrl}/authors/${author.slug}`);
|
];
|
||||||
|
|
||||||
return [
|
// Author pages
|
||||||
...mainPages,
|
const authorPages = authors.map(author => `${baseUrl}/authors/${author.slug}`);
|
||||||
...freeTools,
|
|
||||||
...useCasePages,
|
return [
|
||||||
...germanPages,
|
...mainPages,
|
||||||
...blogPages,
|
...freeTools,
|
||||||
...learnPages,
|
...useCasePages,
|
||||||
...authorPages,
|
...germanPages,
|
||||||
...alternativesPages,
|
...blogPages,
|
||||||
...pseoPages,
|
...learnPages,
|
||||||
...guidePages,
|
...authorPages,
|
||||||
...industryHubPages,
|
...alternativesPages,
|
||||||
];
|
...pseoPages,
|
||||||
}
|
...guidePages,
|
||||||
|
...industryHubPages,
|
||||||
// If run directly
|
];
|
||||||
if (require.main === module) {
|
}
|
||||||
const urls = getAllIndexableUrls();
|
|
||||||
submitToIndexNow(urls);
|
// If run directly
|
||||||
}
|
if (require.main === module) {
|
||||||
|
const urls = getAllIndexableUrls();
|
||||||
|
submitToIndexNow(urls);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user