feat: update specialty URL generation logic and improve indexing strategy for specialties
This commit is contained in:
+15
-29
@@ -158,35 +158,21 @@ async function getClinicUrls(baseUrl, scope) {
|
||||
|
||||
// صفحات فرود تخصص per-domain — روی هر دامنه «تخصص + آن شهر» است، پس همهجا self.
|
||||
//
|
||||
// فقط تخصصهایی که در همین دامنه واقعاً پزشک دارند اعلام میشوند؛ تولید بیقید هر ۹۳
|
||||
// تخصص برای هر ۳۵ دامنه هزاران صفحهٔ خالی به گوگل معرفی میکرد (thin content انبوه).
|
||||
// هر تخصص ایندکسپذیر روی هر دامنه اعلام میشود، مستقل از اینکه امروز در آن شهر پزشک
|
||||
// دارد یا نه — همان سیاستی که صفحه اعمال میکند. اگر sitemap به تعداد پزشکان گره
|
||||
// میخورد، صفحهٔ ایندکسپذیرِ اعلامنشده میساختیم و با هر افت و خیز داده، URLها از
|
||||
// sitemap در میآمدند و برمیگشتند.
|
||||
//
|
||||
// منبع، همان پزشکانی است که این sitemap منتشرشان میکند — نه endpoint شمارش. آن
|
||||
// endpoint با فیلتر لیست پزشکان اختلاف دارد (مثلاً پزشکِ یافتشده از آدرس کلینیک را
|
||||
// نمیشمارد)، و اگر sitemap از یک منبع و خودِ صفحه از منبع دیگر تصمیم بگیرد، صفحهٔ
|
||||
// ایندکسپذیرِ اعلامنشده یا برعکس میسازیم. اینطور هیچ فراخوانی اضافهای هم ندارد.
|
||||
function getSpecialtyUrls(baseUrl, doctors) {
|
||||
// والدها noindex هستند (lib/specialtyIndexing)؛ اعلامشان در sitemap سیگنال
|
||||
// متناقض به گوگل میدهد، پس اصلاً منتشر نمیشوند.
|
||||
const slugById = new Map(
|
||||
specialtiesData
|
||||
.filter((s) => s?.slug && s.status === 1 && isIndexableSpecialty(s))
|
||||
.map((s) => [String(s.id), s.slug])
|
||||
);
|
||||
|
||||
const slugs = new Set();
|
||||
for (const doctor of doctors) {
|
||||
for (const specialty of doctor?.specialties ?? []) {
|
||||
const slug = slugById.get(String(specialty?.id));
|
||||
if (slug) slugs.add(slug);
|
||||
}
|
||||
}
|
||||
|
||||
return [...slugs].map((slug) => ({
|
||||
url: `${baseUrl}/specialties/${slug}`,
|
||||
changeFrequency: 'weekly',
|
||||
priority: 0.8,
|
||||
}));
|
||||
// دستههای سطحبالا (lib/specialtyIndexing) noindex هستند؛ اعلامشان سیگنال متناقض
|
||||
// به گوگل میدهد، پس منتشر نمیشوند.
|
||||
function getSpecialtyUrls(baseUrl) {
|
||||
return specialtiesData
|
||||
.filter((s) => s?.slug && s.status === 1 && isIndexableSpecialty(s))
|
||||
.map((s) => ({
|
||||
url: `${baseUrl}/specialties/${s.slug}`,
|
||||
changeFrequency: 'weekly',
|
||||
priority: 0.8,
|
||||
}));
|
||||
}
|
||||
|
||||
// هر پست فقط در sitemap دامنهٔ canonical خودش: پست شهریافته → دامنهٔ آن شهر،
|
||||
@@ -231,7 +217,7 @@ export default async function sitemap() {
|
||||
|
||||
const allUrls = [
|
||||
...getStaticPages(baseUrl),
|
||||
...getSpecialtyUrls(baseUrl, doctors),
|
||||
...getSpecialtyUrls(baseUrl),
|
||||
...doctorUrls,
|
||||
...clinicUrls,
|
||||
...blogUrls,
|
||||
|
||||
@@ -54,14 +54,13 @@ export async function generateMetadata({ params }) {
|
||||
const description = `لیست بهترین پزشکان ${specialty.name} در ${cityName} همراه با نشانی مطب، ساعات کاری و امتیاز بیماران. رزرو نوبت آنلاین متخصص ${specialty.name}.`;
|
||||
const image = "/assets/images/og-image.png";
|
||||
|
||||
// تخصصی که در این شهر پزشکی ندارد فقط یک عنوان و متن قالبی است — thin content.
|
||||
// ایندکس نمیشود (و در sitemap هم نمیآید)، ولی follow میماند تا لینکهای
|
||||
// داخلیاش دنبال شوند. بهمحض افزودهشدن اولین پزشک، خودکار ایندکسپذیر میشود.
|
||||
const { total } = await getDoctors(specialty.id, isRoot ? null : matchedCity?.id);
|
||||
|
||||
// دستهٔ سطحبالا (دارای زیرشاخهٔ فعال) محتوای مستقلی ندارد و با فرزندانش روی همان
|
||||
// کوئری رقابت میکند؛ صفحهٔ قابلایندکس، همان زیرشاخه است.
|
||||
const noindex = isCategorySpecialty(specialty) || total === 0;
|
||||
// ایندکس به تعداد پزشکان شهر گره نمیخورد: صفحه روی هر دامنه متن مقدمه و FAQ یکتای
|
||||
// خودش را دارد (buildSpecialtyIntro با هشِ تخصص+شهر واگرا میشود) و شهری که امروز
|
||||
// پزشک ندارد فردا دارد — نوسان ایندکس بدتر از صفحهٔ کمپزشک است.
|
||||
//
|
||||
// تنها استثنا دستهٔ سطحبالاست (دارای زیرشاخهٔ فعال): محتوای مستقلی ندارد و با
|
||||
// فرزندانش روی همان کوئری رقابت میکند؛ صفحهٔ قابلایندکس، همان زیرشاخه است.
|
||||
const noindex = isCategorySpecialty(specialty);
|
||||
|
||||
return {
|
||||
title,
|
||||
|
||||
Reference in New Issue
Block a user