feat: add canonical URL handling and entity quality checks
- Implemented canonical URL strategies for city-specific domains and entities. - Added helper functions for domain and city resolution. - Created tests for canonical URL generation and domain resolution. - Introduced entity quality checks for doctors and clinics to ensure meaningful content. - Developed unique introductory texts for listing pages to avoid duplicate content. - Established robots.txt policies for listing pages to manage indexing based on user filters. - Enhanced specialty content with dynamic introductions and FAQs to improve SEO.
This commit is contained in:
+68
-17
@@ -1,21 +1,72 @@
|
||||
function Pageguide({ list }) {
|
||||
import Link from "next/link";
|
||||
import { safeJsonLd } from "@/lib/sanitize";
|
||||
|
||||
// Breadcrumb واحد سایت: ظاهر دقیقاً همان نسخهٔ قبلی (همان کلاسها، همان جداکنندهٔ «>»)
|
||||
// ولی ساختار سمانتیک درست (nav/ol/a) و BreadcrumbList از همان یک منبع داده تولید میشود
|
||||
// تا نسخهٔ بصری و schema هرگز واگرا نشوند.
|
||||
//
|
||||
// list: Array<string | { name, href }> — آیتم آخر همیشه صفحهٔ جاری است (بدون لینک).
|
||||
|
||||
const ITEM_CLASS = "text-[16px] font-normal";
|
||||
|
||||
function normalize(list) {
|
||||
return list
|
||||
.map((item) => (typeof item === "string" ? { name: item } : item))
|
||||
.filter((item) => item?.name);
|
||||
}
|
||||
|
||||
function Pageguide({ list = [], origin }) {
|
||||
const items = normalize(list);
|
||||
if (items.length === 0) return null;
|
||||
|
||||
const jsonLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: items.map((item, idx) => ({
|
||||
"@type": "ListItem",
|
||||
position: idx + 1,
|
||||
name: item.name,
|
||||
...(item.href && origin && { item: `${origin}${item.href}` }),
|
||||
})),
|
||||
};
|
||||
|
||||
return (
|
||||
<ul className="flex items-center justify-start gap-1">
|
||||
{list.map((item, idx) => (
|
||||
<li key={idx} className="flex items-center justify-start gap-1">
|
||||
<h2
|
||||
className={`text-[16px] font-normal ${ list.length > idx + 1 ? "text-[#9B9B9B]" : "text-[#525252]" } `}
|
||||
>
|
||||
{item}
|
||||
</h2>
|
||||
<span
|
||||
className={` text-[#9B9B9B] text-[16px] font-normal ${list.length > idx + 1 ? "flex" : "hidden"} `}
|
||||
>
|
||||
{">"}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: safeJsonLd(jsonLd) }}
|
||||
/>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol className="flex items-center justify-start gap-1">
|
||||
{items.map((item, idx) => {
|
||||
const isLast = idx === items.length - 1;
|
||||
const colorClass = isLast ? "text-[#525252]" : "text-[#9B9B9B]";
|
||||
return (
|
||||
<li key={idx} className="flex items-center justify-start gap-1">
|
||||
{item.href && !isLast ? (
|
||||
<Link href={item.href} className={`${ITEM_CLASS} ${colorClass}`}>
|
||||
{item.name}
|
||||
</Link>
|
||||
) : (
|
||||
<span
|
||||
className={`${ITEM_CLASS} ${colorClass}`}
|
||||
{...(isLast && { "aria-current": "page" })}
|
||||
>
|
||||
{item.name}
|
||||
</span>
|
||||
)}
|
||||
<span
|
||||
className={`text-[#9B9B9B] ${ITEM_CLASS} ${isLast ? "hidden" : "flex"}`}
|
||||
aria-hidden="true"
|
||||
>
|
||||
{">"}
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ol>
|
||||
</nav>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user