Ahrefs 96->100
This commit is contained in:
parent
0a02876ea4
commit
83ea141230
|
|
@ -0,0 +1 @@
|
||||||
|
bb6dfaacf1ed41a880281c426c54ed7c
|
||||||
|
|
@ -4,7 +4,7 @@ import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
const HOST = 'www.qrmaster.net';
|
const HOST = 'www.qrmaster.net';
|
||||||
const KEY = '1234567890abcdef';
|
const KEY = 'bb6dfaacf1ed41a880281c426c54ed7c';
|
||||||
const KEY_LOCATION = `https://${HOST}/${KEY}.txt`;
|
const KEY_LOCATION = `https://${HOST}/${KEY}.txt`;
|
||||||
const INDEXNOW_ENDPOINT = 'https://api.indexnow.org/indexnow';
|
const INDEXNOW_ENDPOINT = 'https://api.indexnow.org/indexnow';
|
||||||
|
|
||||||
|
|
|
||||||
1143
seo_issues_new.md
1143
seo_issues_new.md
File diff suppressed because it is too large
Load Diff
|
|
@ -7,7 +7,14 @@ import AppLayout from './AppLayout';
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Dashboard | QR Master',
|
title: 'Dashboard | QR Master',
|
||||||
description: 'Manage your QR Master dashboard. Create dynamic QR codes, view real-time scan analytics, and configure your account settings in one secure place.',
|
description: 'Manage your QR Master dashboard. Create dynamic QR codes, view real-time scan analytics, and configure your account settings in one secure place.',
|
||||||
robots: { index: false, follow: false }, // Dashboard pages shouldn't be indexed generally
|
robots: { index: false, follow: false },
|
||||||
|
icons: {
|
||||||
|
icon: [
|
||||||
|
{ url: '/favicon.svg', type: 'image/svg+xml' },
|
||||||
|
{ url: '/logo.svg', type: 'image/svg+xml' },
|
||||||
|
],
|
||||||
|
apple: '/logo.svg',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootAppLayout({
|
export default function RootAppLayout({
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,13 @@ import type { Metadata } from 'next';
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'Authentication | QR Master',
|
title: 'Authentication | QR Master',
|
||||||
description: 'Securely login or sign up to QR Master to manage your dynamic QR codes, track analytics, and access premium features. Your gateway to professional QR management.',
|
description: 'Securely login or sign up to QR Master to manage your dynamic QR codes, track analytics, and access premium features. Your gateway to professional QR management.',
|
||||||
|
icons: {
|
||||||
|
icon: [
|
||||||
|
{ url: '/favicon.svg', type: 'image/svg+xml' },
|
||||||
|
{ url: '/logo.svg', type: 'image/svg+xml' },
|
||||||
|
],
|
||||||
|
apple: '/logo.svg',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function AuthRootLayout({
|
export default function AuthRootLayout({
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,24 @@ export const metadata: Metadata = {
|
||||||
alternates: {
|
alternates: {
|
||||||
canonical: 'https://www.qrmaster.net/login',
|
canonical: 'https://www.qrmaster.net/login',
|
||||||
},
|
},
|
||||||
|
openGraph: {
|
||||||
|
title: 'Login to QR Master | Access Your Dashboard',
|
||||||
|
description: 'Sign in to QR Master to create, manage, and track your QR codes.',
|
||||||
|
url: 'https://www.qrmaster.net/login',
|
||||||
|
type: 'website',
|
||||||
|
images: [{
|
||||||
|
url: 'https://www.qrmaster.net/og-image.png',
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
alt: 'QR Master Login',
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: 'summary_large_image',
|
||||||
|
title: 'Login to QR Master | Access Your Dashboard',
|
||||||
|
description: 'Sign in to QR Master to create, manage, and track your QR codes.',
|
||||||
|
images: ['https://www.qrmaster.net/og-image.png'],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,24 @@ export const metadata: Metadata = {
|
||||||
alternates: {
|
alternates: {
|
||||||
canonical: 'https://www.qrmaster.net/signup',
|
canonical: 'https://www.qrmaster.net/signup',
|
||||||
},
|
},
|
||||||
|
openGraph: {
|
||||||
|
title: 'Create Free Account | QR Master',
|
||||||
|
description: 'Sign up for QR Master to create free QR codes with tracking and customization.',
|
||||||
|
url: 'https://www.qrmaster.net/signup',
|
||||||
|
type: 'website',
|
||||||
|
images: [{
|
||||||
|
url: 'https://www.qrmaster.net/og-image.png',
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
alt: 'QR Master Sign Up',
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: 'summary_large_image',
|
||||||
|
title: 'Create Free Account | QR Master',
|
||||||
|
description: 'Sign up for QR Master to create free QR codes with tracking and customization.',
|
||||||
|
images: ['https://www.qrmaster.net/og-image.png'],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { ObfuscatedMailto } from '@/components/ui/ObfuscatedMailto';
|
||||||
|
|
||||||
|
export function ContactSupport() {
|
||||||
|
return (
|
||||||
|
<div className="mt-16 bg-blue-50 border-l-4 border-blue-500 p-8 rounded-r-lg">
|
||||||
|
<h2 className="text-2xl font-bold mb-4 text-gray-900">
|
||||||
|
Still have questions?
|
||||||
|
</h2>
|
||||||
|
<p className="text-lg text-gray-700 mb-6 leading-relaxed">
|
||||||
|
Our support team is here to help. Contact us at{' '}
|
||||||
|
<ObfuscatedMailto
|
||||||
|
email="support@qrmaster.net"
|
||||||
|
className="text-blue-600 hover:text-blue-700 font-semibold"
|
||||||
|
/>{' '}
|
||||||
|
or reach out through our live chat.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ import type { Metadata } from 'next';
|
||||||
import SeoJsonLd from '@/components/SeoJsonLd';
|
import SeoJsonLd from '@/components/SeoJsonLd';
|
||||||
import { faqPageSchema } from '@/lib/schema';
|
import { faqPageSchema } from '@/lib/schema';
|
||||||
import { Card, CardContent } from '@/components/ui/Card';
|
import { Card, CardContent } from '@/components/ui/Card';
|
||||||
|
import { ContactSupport } from './ContactSupport';
|
||||||
|
|
||||||
function truncateAtWord(text: string, maxLength: number): string {
|
function truncateAtWord(text: string, maxLength: number): string {
|
||||||
if (text.length <= maxLength) return text;
|
if (text.length <= maxLength) return text;
|
||||||
|
|
@ -131,18 +132,7 @@ export default function FAQPage() {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-16 bg-blue-50 border-l-4 border-blue-500 p-8 rounded-r-lg">
|
<ContactSupport />
|
||||||
<h2 className="text-2xl font-bold mb-4 text-gray-900">
|
|
||||||
Still have questions?
|
|
||||||
</h2>
|
|
||||||
<p className="text-lg text-gray-700 mb-6 leading-relaxed">
|
|
||||||
Our support team is here to help. Contact us at{' '}
|
|
||||||
<a href="mailto:support@qrmaster.net" className="text-blue-600 hover:text-blue-700 font-semibold">
|
|
||||||
support@qrmaster.net
|
|
||||||
</a>{' '}
|
|
||||||
or reach out through our live chat.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { Badge } from '@/components/ui/Badge';
|
||||||
import { showToast } from '@/components/ui/Toast';
|
import { showToast } from '@/components/ui/Toast';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { BillingToggle } from '@/components/ui/BillingToggle';
|
import { BillingToggle } from '@/components/ui/BillingToggle';
|
||||||
|
import { ObfuscatedMailto } from '@/components/ui/ObfuscatedMailto';
|
||||||
|
|
||||||
export default function PricingClient() {
|
export default function PricingClient() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -182,9 +183,9 @@ export default function PricingClient() {
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto px-4 py-12">
|
<div className="container mx-auto px-4 py-12">
|
||||||
<div className="text-center mb-12">
|
<div className="text-center mb-12">
|
||||||
<h1 className="text-4xl font-bold text-gray-900 mb-4">
|
<h2 className="text-4xl font-bold text-gray-900 mb-4">
|
||||||
Choose Your Plan
|
Choose Your Plan
|
||||||
</h1>
|
</h2>
|
||||||
<p className="text-xl text-gray-600">
|
<p className="text-xl text-gray-600">
|
||||||
Select the perfect plan for your QR code needs
|
Select the perfect plan for your QR code needs
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -260,7 +261,7 @@ export default function PricingClient() {
|
||||||
All plans include unlimited static QR codes and basic customization.
|
All plans include unlimited static QR codes and basic customization.
|
||||||
</p>
|
</p>
|
||||||
<p className="text-gray-600 mt-2">
|
<p className="text-gray-600 mt-2">
|
||||||
Need help choosing? <a href="mailto:support@qrmaster.net" className="text-primary-600 hover:text-primary-700 underline">Contact our team</a>
|
Need help choosing? <ObfuscatedMailto email="support@qrmaster.net" className="text-primary-600 hover:text-primary-700 underline">Contact our team</ObfuscatedMailto>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { ObfuscatedMailto } from '@/components/ui/ObfuscatedMailto';
|
||||||
|
|
||||||
|
export function PrivacyEmailLink() {
|
||||||
|
return (
|
||||||
|
<ObfuscatedMailto
|
||||||
|
email="support@qrmaster.net"
|
||||||
|
className="text-primary-600 hover:text-primary-700"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import { PrivacyEmailLink } from './PrivacyEmailLink';
|
||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: 'Privacy Policy | QR Master',
|
title: 'Privacy Policy | QR Master',
|
||||||
|
|
@ -110,9 +111,7 @@ export default function PrivacyPage() {
|
||||||
</ul>
|
</ul>
|
||||||
<p className="text-gray-700 mb-4">
|
<p className="text-gray-700 mb-4">
|
||||||
To exercise these rights, contact us at{' '}
|
To exercise these rights, contact us at{' '}
|
||||||
<a href="mailto:support@qrmaster.net" className="text-primary-600 hover:text-primary-700">
|
<PrivacyEmailLink />
|
||||||
support@qrmaster.net
|
|
||||||
</a>
|
|
||||||
</p>
|
</p>
|
||||||
<p className="text-gray-700 mb-4">
|
<p className="text-gray-700 mb-4">
|
||||||
Our service is for users 16 years and older. If you're in the EEA and have concerns,
|
Our service is for users 16 years and older. If you're in the EEA and have concerns,
|
||||||
|
|
@ -128,9 +127,7 @@ export default function PrivacyPage() {
|
||||||
<div className="bg-gray-50 p-6 rounded-lg">
|
<div className="bg-gray-50 p-6 rounded-lg">
|
||||||
<p className="text-gray-700 mb-2">
|
<p className="text-gray-700 mb-2">
|
||||||
<strong>Email:</strong>{' '}
|
<strong>Email:</strong>{' '}
|
||||||
<a href="mailto:support@qrmaster.net" className="text-primary-600 hover:text-primary-700">
|
<PrivacyEmailLink />
|
||||||
support@qrmaster.net
|
|
||||||
</a>
|
|
||||||
</p>
|
</p>
|
||||||
<p className="text-gray-700 mb-2"><strong>Website:</strong> <a href="/" className="text-primary-600 hover:text-primary-700">qrmaster.net</a></p>
|
<p className="text-gray-700 mb-2"><strong>Website:</strong> <a href="/" className="text-primary-600 hover:text-primary-700">qrmaster.net</a></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,13 @@ import '@/styles/globals.css';
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: 'vCard Download',
|
title: 'vCard Download',
|
||||||
description: 'Download contact information',
|
description: 'Download contact information',
|
||||||
|
icons: {
|
||||||
|
icon: [
|
||||||
|
{ url: '/favicon.svg', type: 'image/svg+xml' },
|
||||||
|
{ url: '/logo.svg', type: 'image/svg+xml' },
|
||||||
|
],
|
||||||
|
apple: '/logo.svg',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function VCardLayout({
|
export default function VCardLayout({
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@ export default function SeoJsonLd({ data }: SeoJsonLdProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{jsonLdArray.map((item, index) => {
|
{jsonLdArray.map((item, index) => {
|
||||||
const schema = {
|
// Only add @context if it doesn't already exist in the item
|
||||||
'@context': 'https://schema.org',
|
const schema = (item as any)['@context']
|
||||||
...item,
|
? item
|
||||||
};
|
: { '@context': 'https://schema.org', ...item };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<script
|
<script
|
||||||
|
|
|
||||||
|
|
@ -66,9 +66,9 @@ export const Hero: React.FC<HeroProps> = ({ t }) => {
|
||||||
transition={{ duration: 0.5 }}
|
transition={{ duration: 0.5 }}
|
||||||
className="space-y-6"
|
className="space-y-6"
|
||||||
>
|
>
|
||||||
<h1 className="text-5xl lg:text-6xl font-bold text-gray-900 leading-tight">
|
<h2 className="text-5xl lg:text-6xl font-bold text-gray-900 leading-tight">
|
||||||
{t.hero.title}
|
{t.hero.title}
|
||||||
</h1>
|
</h2>
|
||||||
|
|
||||||
<p className="text-xl text-gray-600 leading-relaxed max-w-2xl">
|
<p className="text-xl text-gray-600 leading-relaxed max-w-2xl">
|
||||||
{t.hero.subtitle}
|
{t.hero.subtitle}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
interface ObfuscatedMailtoProps {
|
||||||
|
email: string;
|
||||||
|
className?: string;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders an email link that only becomes a clickable mailto: link after client-side hydration.
|
||||||
|
* This prevents Cloudflare's Email Obfuscation from breaking the link in the static HTML,
|
||||||
|
* which causes crawlers like Ahrefs to report 404 errors on /cdn-cgi/l/email-protection.
|
||||||
|
*/
|
||||||
|
export function ObfuscatedMailto({ email, className, children }: ObfuscatedMailtoProps) {
|
||||||
|
const [isMounted, setIsMounted] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsMounted(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Before hydration, render as plain text/span to avoid Cloudflare manipulation
|
||||||
|
if (!isMounted) {
|
||||||
|
return <span className={className}>{children || email}</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// After hydration, render as a proper mailto link
|
||||||
|
return (
|
||||||
|
<a href={`mailto:${email}`} className={className}>
|
||||||
|
{children || email}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -21,7 +21,7 @@ export const blogPosts: Record<string, BlogPostData> = {
|
||||||
'qr-code-analytics': {
|
'qr-code-analytics': {
|
||||||
slug: 'qr-code-analytics',
|
slug: 'qr-code-analytics',
|
||||||
title: 'QR Code Analytics: The Complete Guide',
|
title: 'QR Code Analytics: The Complete Guide',
|
||||||
excerpt: 'Master QR Code Analytics with our complete guide. Learn how to track scans, measure ROI, and optimize your marketing campaigns using real-time data and insights.',
|
excerpt: 'Master QR Code Analytics with our complete guide. Learn how to track scans, measure ROI, and optimize your marketing campaigns using real-time data.',
|
||||||
date: 'October 16, 2025',
|
date: 'October 16, 2025',
|
||||||
datePublished: '2025-10-16T09:00:00Z',
|
datePublished: '2025-10-16T09:00:00Z',
|
||||||
dateModified: '2025-10-16T09:00:00Z',
|
dateModified: '2025-10-16T09:00:00Z',
|
||||||
|
|
@ -142,7 +142,7 @@ export const blogPosts: Record<string, BlogPostData> = {
|
||||||
'qr-code-tracking-guide-2025': {
|
'qr-code-tracking-guide-2025': {
|
||||||
slug: 'qr-code-tracking-guide-2025',
|
slug: 'qr-code-tracking-guide-2025',
|
||||||
title: 'QR Code Tracking: Complete Guide 2025',
|
title: 'QR Code Tracking: Complete Guide 2025',
|
||||||
excerpt: 'The complete guide to QR Code Tracking in 2025. Learn how to track scans, measure ROI with analytics tools, and optimize your marketing campaigns for maximum engagement.',
|
excerpt: 'The complete guide to QR Code Tracking in 2025. Learn how to track scans, measure ROI, and optimize your marketing campaigns.',
|
||||||
date: 'October 18, 2025',
|
date: 'October 18, 2025',
|
||||||
datePublished: '2025-10-18T09:00:00Z',
|
datePublished: '2025-10-18T09:00:00Z',
|
||||||
dateModified: '2025-10-18T09:00:00Z',
|
dateModified: '2025-10-18T09:00:00Z',
|
||||||
|
|
@ -668,7 +668,7 @@ app.get('/qr/:id', async (req, res) => {
|
||||||
'dynamic-vs-static-qr-codes': {
|
'dynamic-vs-static-qr-codes': {
|
||||||
slug: 'dynamic-vs-static-qr-codes',
|
slug: 'dynamic-vs-static-qr-codes',
|
||||||
title: 'Dynamic vs Static QR Codes: The Ultimate Comparison',
|
title: 'Dynamic vs Static QR Codes: The Ultimate Comparison',
|
||||||
excerpt: 'Static vs Dynamic QR Codes: Which one should you choose? Learn the key differences, pros and cons, and why dynamic QR codes are the better choice for business and marketing.',
|
excerpt: 'Static vs Dynamic QR Codes: Which should you choose? Learn the key differences, pros and cons, and why dynamic codes are better for business.',
|
||||||
date: 'October 17, 2025',
|
date: 'October 17, 2025',
|
||||||
datePublished: '2025-10-17T09:00:00Z',
|
datePublished: '2025-10-17T09:00:00Z',
|
||||||
dateModified: '2025-10-17T09:00:00Z',
|
dateModified: '2025-10-17T09:00:00Z',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue