SEO blog post

This commit is contained in:
2026-08-05 19:32:52 +02:00
parent 94bf162062
commit 8c50bf71c5
21 changed files with 7976 additions and 4355 deletions

View File

@@ -8,6 +8,25 @@ type Props = {
title?: string;
};
const COMPETITOR_DOMAINS = [
'bitly.com',
'qrcode-tiger.com',
'qr-code-generator.com',
'flowcode.com',
'beaconstac.com',
'uniqode.com',
'qrfy.com',
];
function isCompetitor(url: string): boolean {
try {
const host = new URL(url).hostname.replace(/^www\./, '');
return COMPETITOR_DOMAINS.some((d) => host === d || host.endsWith(`.${d}`));
} catch {
return false;
}
}
export function SourcesList({ sources, title = "Sources & References" }: Props) {
if (!sources?.length) return null;
@@ -21,7 +40,11 @@ export function SourcesList({ sources, title = "Sources & References" }: Props)
<a
href={source.url}
target="_blank"
rel="noopener noreferrer"
rel={
isCompetitor(source.url)
? "noopener noreferrer nofollow"
: "noopener noreferrer"
}
className="text-blue-600 hover:text-blue-800 hover:underline"
>
{source.name}

View File

@@ -85,8 +85,8 @@ export function Footer({ variant = 'marketing', t }: FooterProps) {
<li><Link href="/manage-qr-codes" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>Manage QR Codes</Link></li>
<li><Link href="/custom-qr-code-generator" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>Custom QR</Link></li>
<li><Link href="/qr-code-for-marketing-campaigns" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>Campaign QR Codes</Link></li>
<li><Link href="/guide/tracking-analytics" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>Tracking Guide</Link></li>
<li><Link href="/guide/qr-code-best-practices" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>Best Practices</Link></li>
<li><Link href="/learn/tracking" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>Tracking Guide</Link></li>
<li><Link href="/learn/basics" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>Best Practices</Link></li>
</ul>
</div>
@@ -133,10 +133,10 @@ export function Footer({ variant = 'marketing', t }: FooterProps) {
<li><a href="https://open-vsx.org/extension/qrmaster/qrmaster-generator" target="_blank" rel="noopener noreferrer" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>VS Code / Cursor Extension</a></li>
<li><a href="https://github.com/marketplace/actions/qr-master-code-generator" target="_blank" rel="noopener noreferrer" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>GitHub Action Marketplace</a></li>
<li><a href="https://www.npmjs.com/package/qrmaster-cli" target="_blank" rel="noopener noreferrer" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>npm Package (Node.js)</a></li>
<li><a href="https://pypi.org/project/qrmaster/" target="_blank" rel="noopener noreferrer" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>PyPI Package (Python)</a></li>
<li><a href="https://github.com/knuthtimo-lab/qrmaster-cli" target="_blank" rel="noopener noreferrer" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>GitHub Repository</a></li>
<li><a href="https://chromewebstore.google.com" target="_blank" rel="noopener noreferrer" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>Chrome Web Store Extension (Soon)</a></li>
</ul>
<li><a href="https://pypi.org/project/qrmaster/" target="_blank" rel="noopener noreferrer" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>PyPI Package (Python)</a></li>
<li><a href="https://github.com/knuthtimo-lab/qrmaster-cli" target="_blank" rel="noopener noreferrer" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>GitHub Repository</a></li>
<li><a href="https://chromewebstore.google.com" target="_blank" rel="noopener noreferrer" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>Chrome Web Store Extension (Soon)</a></li>
</ul>
</div>
</div>

File diff suppressed because it is too large Load Diff

View File

@@ -121,11 +121,12 @@ export function getAllIndexableUrls(): string[] {
...publishedGuidePages.map(page => `${baseUrl}${page.canonicalPath}`),
];
// Standalone guide pages (not part of the pSEO [slug] route)
// Learn hub pillars (the /guide/* URLs these replaced are 301'd in next.config.mjs
// and must never be submitted to IndexNow - see redirects() there)
const guidePages = [
`${baseUrl}/guide/bulk-qr-code-generation`,
`${baseUrl}/guide/qr-code-best-practices`,
`${baseUrl}/guide/tracking-analytics`,
`${baseUrl}/learn/developer`,
`${baseUrl}/learn/basics`,
`${baseUrl}/learn/tracking`,
];
// Industry landing pages