Implement multi-domain SEO improvements:

- Add metadata to login and login-verify pages to prevent indexing.
- Update robots.txt to disallow additional sensitive paths.
- Enhance sitemap generation to filter by city and include accurate last modified dates.
- Refactor canonical URL generation to support multi-domain architecture, ensuring self-canonicalization for city domains.
- Remove deprecated CanonicalHandler component and streamline canonical URL handling.
- Introduce safe JSON-LD output to prevent XSS vulnerabilities.
- Add payment layout with appropriate metadata to prevent indexing.
- Conduct a comprehensive technical SEO audit and implement necessary fixes across the application.
This commit is contained in:
hamed
2026-07-05 15:47:47 +03:30
parent 522caf6b1b
commit b04bb45ca1
24 changed files with 595 additions and 329 deletions
+31 -11
View File
@@ -6,11 +6,21 @@ import "react-toastify/dist/ReactToastify.css";
import CustomToastify from "./CustomToastify";
import { ProvinceProvider } from "@/context/ProvinceProvider";
import { getStateInfo } from "@/lib/getStateInfo";
import { getCanonicalUrl } from "@/lib/getCanonicalUrl";
import { getCanonicalUrl, buildCanonicalUrl, getRequestOrigin } from "@/lib/getCanonicalUrl";
import { safeJsonLd } from "@/lib/sanitize";
import { headers } from "next/headers";
export const viewport = {
width: "device-width",
initialScale: 1,
};
export async function generateMetadata() {
const { matchedCity } = await getStateInfo();
const headersList = await headers();
const metadataBase = new URL(buildCanonicalUrl(headersList.get("host"), "/"));
const canonicalUrl = await getCanonicalUrl();
const title =
@@ -21,6 +31,7 @@ export async function generateMetadata() {
const description = matchedCity?.description || "نوبت 724 - سیستم آنلاین نوبت‌دهی برای پزشکان و کلینیک‌ها. با استفاده از نوبت 724، به راحتی نوبت پزشکی خود را به صورت آنلاین رزرو کنید و از خدمات سریع و کارآمد ما بهره‌مند شوید";
const baseMetadata = {
metadataBase,
title,
description,
keywords: matchedCity
@@ -32,13 +43,13 @@ export async function generateMetadata() {
type: "website",
locale: "fa_IR",
siteName: matchedCity?.site_name || "نوبت 724",
images: ["https://www.nobat724.com/assets/images/logo.png"],
images: ["https://nobat724.com/assets/images/logo.png"],
},
twitter: {
card: "summary_large_image",
title,
description,
images: ["https://www.nobat724.com/assets/images/logo.png"],
images: ["https://nobat724.com/assets/images/logo.png"],
},
};
@@ -59,8 +70,7 @@ export async function generateMetadata() {
};
}
// Add canonical URL only if we're not on the main domain and matchedCity domain is not nobat724.com
if (canonicalUrl && (!matchedCity || matchedCity.domain !== 'nobat724.com')) {
if (canonicalUrl) {
baseMetadata.alternates = {
canonical: canonicalUrl,
};
@@ -72,7 +82,7 @@ export async function generateMetadata() {
export default async function RootLayout({ children }) {
const { matchedCity } = await getStateInfo();
const siteName = matchedCity?.site_name || "نوبت 724";
const siteUrl = "https://www.nobat724.com";
const siteUrl = await getRequestOrigin();
const organizationJsonLd = {
"@context": "https://schema.org",
@@ -97,17 +107,27 @@ export default async function RootLayout({ children }) {
return (
<html lang="fa" dir="rtl" suppressHydrationWarning>
<head>
<meta
name="viewport"
content="width=device-width,initial-scale=1"
<link
rel="preload"
href="/fonts/vazir/Vazirmatn-RD-FD-Regular.ttf"
as="font"
type="font/ttf"
crossOrigin="anonymous"
/>
<link
rel="preload"
href="/fonts/vazir/Vazirmatn-RD-FD-Bold.ttf"
as="font"
type="font/ttf"
crossOrigin="anonymous"
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(organizationJsonLd) }}
dangerouslySetInnerHTML={{ __html: safeJsonLd(organizationJsonLd) }}
/>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(websiteJsonLd) }}
dangerouslySetInnerHTML={{ __html: safeJsonLd(websiteJsonLd) }}
/>
</head>
<ThemeRegistry>