diff --git a/blog_roadmap.md b/blog_roadmap.md new file mode 100644 index 0000000..56d90be --- /dev/null +++ b/blog_roadmap.md @@ -0,0 +1,83 @@ +📅 Blog Content Roadmap (Q1 2026) +Goal: Publish 20 high-quality SEO posts over 60 days (Jan 29 - Mar 27). Cadence: Every 3 days. Strategy: "Strict 404 Gate" (Future posts are invisible/404 until publish date). + +✅ Completed (Ready to Ship) +Jan 29: +Free Barcode Generator (Online) +Status: 🟢 Ready (Content Complete + SEO Optimized + Hero Image Generated). +Key Feature: Quick Answer Box, SVG/PNG Comparison, FAQ. +🚀 Next Priority: Feb 01 +🎵 Spotify Code Generator: Share Music Instantly +Target Audience: Artists, bands, podcasters, playlist curators. SEO Focus: spotify code generator, create spotify code, music marketing qr, spotify uri to code. + +Drafting Blueprint: + +H1: Spotify Code Generator: Share Songs, Albums & Playlists +Quick Answer: How to get a code (3-step process). +Visual Guide: Where to find the "Spotify URI". +Use Cases: +Merch: T-shirts with album link. +Posters: Gig promotion. +Socials: Instagram Stories overlay. +Critical Comparison (Pro Tip): +Spotify Codes = Cool look, but NO analytics. +Dynamic QR Codes = Less "native" look, but FULL tracking (scans, location, etc.). +Recommendation: Use QR for marketing campaigns where ROI matters; use Spotify Codes for pure branding on merch. +FAQ: Vector download? Do they expire? High-res printing? +CTA: "Generate Music QR Code" (Link to main generator). +Image Concept: + +Style: Neon, vibrant, "Spotify Green" accents, dark mode aesthetic. +Subject: A stylized soundwave transforming into a scannable code, or a vinyl record with a code center. +📋 Upcoming Schedule (Backlog) +Publish Date Topic / Slug Category Status +Feb 04 WhatsApp QR Code (Direct Chat Link) Social ⚪ Pending +Feb 07 Instagram QR Code (Grow Following) Social ⚪ Pending +Feb 10 vCard QR Code (Digital Business Card) Business ⚪ Pending +Feb 13 QR Code Analytics Guide (Deep Dive) Analytics ⚪ Pending +Feb 16 Trackable QR Codes (How-to) Tracking ⚪ Pending +Feb 19 Dynamic vs Static QR (Ultimate Guide) Basics ⚪ Pending +Feb 22 UTM Tracking with QR Codes Marketing ⚪ Pending +Feb 25 QR Code Statistics 2026 Trends ⚪ Pending +Feb 28 Restaurant Menu QR Codes Hospitality ⚪ Pending +Mar 03 QR Codes for Events Events ⚪ Pending +Mar 06 Business Card QR Codes Business ⚪ Pending +Mar 09 Marketing Strategy Examples Marketing ⚪ Pending +Mar 12 Bulk QR Code Generator (Excel/CSV) Bulk ⚪ Pending +Mar 15 Google QR Alternative Comparison ⚪ Pending +Mar 18 Security & Quishing Security ⚪ Pending +Mar 21 Best QR Generator 2026 Review Reviews ⚪ Pending +Mar 24 QR Code API Documentation Developer ⚪ Pending +Mar 27 Free vs Paid Generator Comparison ⚪ Pending +🛠️ Execution Workflow (Repeat for each post) +Select Topic: Take next item from list. +SEO & Outline: Define title, keywords, and H2 structure (use User/Expert persona). +Implement: Replace placeholder content in +src/lib/blog-data.ts +. +Asset: Generate hero image (public/blog/[slug].png) via DALL-E. +Verify: Ensure no build errors and correct 404 behavior if date > now. +✅ SEO Validation Checklist (Target Score: 80+) +1. Page Title + + Focus keyword used at the beginning. + Length: ~60 characters (0 characters available is perfect). +2. Meta Description + + Focus keyword included. + Length: ~160 characters. +3. Content Structure + + H1 contains focus keyword. + First Paragraph contains focus keyword. + Word count: > 600 words (Aim for comprehensive coverage). + Keyword Density: ~2% (e.g., used 4-5 times in 600 words). +4. Assets (Images) + + Image Filename contains focus keyword (e.g., +free-barcode-generator-guide.png +). + Image Alt Tag contains focus keyword. +5. Links + + Add relevant internal links to tools/pricing/other posts. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f35bbaa..0fb645d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,6 +49,7 @@ "react-i18next": "^13.5.0", "react-simple-maps": "^3.0.0", "resend": "^6.4.2", + "sanitize-html": "^2.17.0", "stripe": "^19.1.0", "tailwind-merge": "^2.2.0", "uuid": "^13.0.0", @@ -62,6 +63,7 @@ "@types/qrcode": "^1.5.5", "@types/react": "^18.2.45", "@types/react-dom": "^18.2.18", + "@types/sanitize-html": "^2.16.0", "autoprefixer": "^10.4.16", "cross-env": "^10.1.0", "eslint": "^8.56.0", @@ -4152,6 +4154,16 @@ "@types/react": "^18.0.0" } }, + "node_modules/@types/sanitize-html": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.16.0.tgz", + "integrity": "sha512-l6rX1MUXje5ztPT0cAFtUayXF06DqPhRyfVXareEN5gGCFaP/iwsxIyKODr9XDhfxPpN6vXUFNfo5kZMXCxBtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "htmlparser2": "^8.0.0" + } + }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -6215,6 +6227,15 @@ "dev": true, "license": "MIT" }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -6312,6 +6333,47 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, "node_modules/dompurify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz", @@ -6321,6 +6383,20 @@ "@types/trusted-types": "^2.0.7" } }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dotenv": { "version": "17.2.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", @@ -6393,6 +6469,18 @@ "once": "^1.4.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-abstract": { "version": "1.24.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", @@ -6628,7 +6716,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -8098,6 +8185,25 @@ "node": ">=8.0.0" } }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -8557,6 +8663,15 @@ "node": ">=8" } }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -9823,6 +9938,12 @@ "node": ">=6" } }, + "node_modules/parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==", + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -9948,7 +10069,6 @@ "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -10862,6 +10982,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sanitize-html": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.17.0.tgz", + "integrity": "sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==", + "license": "MIT", + "dependencies": { + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^8.0.0", + "is-plain-object": "^5.0.0", + "parse-srcset": "^1.0.2", + "postcss": "^8.3.11" + } + }, "node_modules/saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", diff --git a/package.json b/package.json index c42cf7a..ad47aef 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "react-i18next": "^13.5.0", "react-simple-maps": "^3.0.0", "resend": "^6.4.2", + "sanitize-html": "^2.17.0", "stripe": "^19.1.0", "tailwind-merge": "^2.2.0", "uuid": "^13.0.0", @@ -81,6 +82,7 @@ "@types/qrcode": "^1.5.5", "@types/react": "^18.2.45", "@types/react-dom": "^18.2.18", + "@types/sanitize-html": "^2.16.0", "autoprefixer": "^10.4.16", "cross-env": "^10.1.0", "eslint": "^8.56.0", diff --git a/public/bb6dfaacf1ed41a880281c426c54ed7c.txt b/public/bb6dfaacf1ed41a880281c426c54ed7c.txt index 44c1146..f202b25 100644 --- a/public/bb6dfaacf1ed41a880281c426c54ed7c.txt +++ b/public/bb6dfaacf1ed41a880281c426c54ed7c.txt @@ -1 +1 @@ -bb6dfaacf1ed41a880281c426c54ed7c +bb6dfaacf1ed41a880281c426c54ed7c diff --git a/public/blog/best-qr-generator-2026.png b/public/blog/best-qr-generator-2026.png new file mode 100644 index 0000000..fc3ab68 Binary files /dev/null and b/public/blog/best-qr-generator-2026.png differ diff --git a/public/blog/free-barcode-generator-guide.png b/public/blog/free-barcode-generator-guide.png new file mode 100644 index 0000000..7007ad2 Binary files /dev/null and b/public/blog/free-barcode-generator-guide.png differ diff --git a/public/blog/free-vs-paid-qr.png b/public/blog/free-vs-paid-qr.png new file mode 100644 index 0000000..a48ed99 Binary files /dev/null and b/public/blog/free-vs-paid-qr.png differ diff --git a/public/blog/instagram-qr-code.png b/public/blog/instagram-qr-code.png new file mode 100644 index 0000000..22fb741 Binary files /dev/null and b/public/blog/instagram-qr-code.png differ diff --git a/public/blog/qr-api.png b/public/blog/qr-api.png new file mode 100644 index 0000000..ee50f95 Binary files /dev/null and b/public/blog/qr-api.png differ diff --git a/public/blog/qr-code-events.png b/public/blog/qr-code-events.png new file mode 100644 index 0000000..88c908b Binary files /dev/null and b/public/blog/qr-code-events.png differ diff --git a/public/blog/qr-marketing-strategy.png b/public/blog/qr-marketing-strategy.png new file mode 100644 index 0000000..ec8f2be Binary files /dev/null and b/public/blog/qr-marketing-strategy.png differ diff --git a/public/blog/qr-security.png b/public/blog/qr-security.png new file mode 100644 index 0000000..4775a1f Binary files /dev/null and b/public/blog/qr-security.png differ diff --git a/public/blog/qr-statistics-2026.png b/public/blog/qr-statistics-2026.png new file mode 100644 index 0000000..e5ca606 Binary files /dev/null and b/public/blog/qr-statistics-2026.png differ diff --git a/public/blog/spotify-qr-code.png b/public/blog/spotify-qr-code.png new file mode 100644 index 0000000..3fa0474 Binary files /dev/null and b/public/blog/spotify-qr-code.png differ diff --git a/public/blog/trackable-qr-codes.png b/public/blog/trackable-qr-codes.png new file mode 100644 index 0000000..0e269e0 Binary files /dev/null and b/public/blog/trackable-qr-codes.png differ diff --git a/public/blog/utm-qr-codes.png b/public/blog/utm-qr-codes.png new file mode 100644 index 0000000..431252c Binary files /dev/null and b/public/blog/utm-qr-codes.png differ diff --git a/public/blog/whatsapp-qr-code.png b/public/blog/whatsapp-qr-code.png new file mode 100644 index 0000000..d047447 Binary files /dev/null and b/public/blog/whatsapp-qr-code.png differ diff --git a/src/app/(main)/(auth)/login/page.tsx b/src/app/(main)/(auth)/login/page.tsx index bf2cbd6..31189e9 100644 --- a/src/app/(main)/(auth)/login/page.tsx +++ b/src/app/(main)/(auth)/login/page.tsx @@ -4,6 +4,10 @@ import LoginClient from './LoginClient'; export const metadata: Metadata = { title: 'QR Master – Smart QR Generator & Analytics', description: 'Create dynamic QR codes, track scans, and scale campaigns with secure analytics. Free advanced features, bulk generation, and custom branding available.', + robots: { + index: false, + follow: true, + }, }; export default function LoginPage() { diff --git a/src/app/(main)/(auth)/signup/page.tsx b/src/app/(main)/(auth)/signup/page.tsx index fe571f6..de34451 100644 --- a/src/app/(main)/(auth)/signup/page.tsx +++ b/src/app/(main)/(auth)/signup/page.tsx @@ -4,6 +4,10 @@ import SignupClient from './SignupClient'; export const metadata: Metadata = { title: 'Create Account | QR Master', description: 'Start creating dynamic QR codes in seconds. Join thousands of businesses using QR Master.', + robots: { + index: false, + follow: true, + }, alternates: { canonical: 'https://www.qrmaster.net/signup', }, diff --git a/src/app/(main)/(marketing)/MarketingLayout.tsx b/src/app/(main)/(marketing)/MarketingLayout.tsx index 1a2e048..971add6 100644 --- a/src/app/(main)/(marketing)/MarketingLayout.tsx +++ b/src/app/(main)/(marketing)/MarketingLayout.tsx @@ -74,6 +74,7 @@ export default function MarketingLayout({
  • Home
  • {t.nav.pricing}
  • {t.nav.blog}
  • +
  • {t.nav.learn}
  • {t.nav.faq}
  • {t.nav.about}
  • {t.nav.contact}
  • @@ -179,6 +180,9 @@ export default function MarketingLayout({ {t.nav.blog} + + {t.nav.learn} + {t.nav.faq} @@ -265,6 +269,7 @@ export default function MarketingLayout({ setMobileMenuOpen(false)}>{t.nav.pricing} setMobileMenuOpen(false)}>{t.nav.about} setMobileMenuOpen(false)}>{t.nav.blog} + setMobileMenuOpen(false)}>{t.nav.learn} setMobileMenuOpen(false)}>{t.nav.faq}
    diff --git a/src/app/(main)/(marketing)/authors/[slug]/page.tsx b/src/app/(main)/(marketing)/authors/[slug]/page.tsx new file mode 100644 index 0000000..ade63f7 --- /dev/null +++ b/src/app/(main)/(marketing)/authors/[slug]/page.tsx @@ -0,0 +1,93 @@ +import { notFound } from "next/navigation"; +import Link from "next/link"; +import Image from "next/image"; +import Script from "next/script"; +import { getAuthorBySlug, getPostsByAuthor } from "@/lib/content"; +import { authors } from "@/lib/author-data"; +import { authorPageSchema } from "@/lib/schema"; + +export function generateMetadata({ params }: { params: { slug: string } }) { + const author = getAuthorBySlug(params.slug); + if (!author) return {}; + return { + title: `${author.name} - ${author.role} | QR Master`, + description: author.bio + }; +} + +export function generateStaticParams() { + return authors.map((author) => ({ + slug: author.slug, + })); +} + +export default function AuthorPage({ params }: { params: { slug: string } }) { + const author = getAuthorBySlug(params.slug); + if (!author) return notFound(); + + const posts = getPostsByAuthor(params.slug); + const jsonLd = authorPageSchema(author, posts); + + return ( +
    +