diff --git a/app/robots.js b/app/robots.js new file mode 100644 index 0000000..877093b --- /dev/null +++ b/app/robots.js @@ -0,0 +1,33 @@ +import { headers } from 'next/headers'; + +// Get current domain from headers +function getCurrentDomain() { + const headersList = headers(); + const host = headersList.get('host'); + return host || 'nobat724.com'; +} + +// Get base URL based on current domain +function getBaseUrl(domain) { + // Remove port number if present (for development) + const cleanDomain = domain.replace(/:\d+$/, ''); + + // For localhost domains, use http, otherwise https + const protocol = cleanDomain.includes('localhost') ? 'http' : 'https'; + + return `${protocol}://${domain}`; +} + +export default function robots() { + const domain = getCurrentDomain(); + const baseUrl = getBaseUrl(domain); + + return { + rules: { + userAgent: '*', + allow: '/', + disallow: '/admin', + }, + sitemap: `${baseUrl}/sitemap.xml`, + }; +} \ No newline at end of file diff --git a/app/sitemap.js b/app/sitemap.js new file mode 100644 index 0000000..4de41bb --- /dev/null +++ b/app/sitemap.js @@ -0,0 +1,252 @@ +import { headers } from 'next/headers'; +import cityData from '../data/city.json'; +import specialtyData from '../data/specialties.json'; +import stateData from '../data/state.json'; +import { + DOMAIN_CONFIG, + isMainDomain, + createSitemapUrl, + createSitemapEntry, + limitArray, + getBaseUrl +} from '../utils/sitemap'; + +// Get current domain from headers +function getCurrentDomain() { + const headersList = headers(); + const host = headersList.get('host'); + return host || DOMAIN_CONFIG.MAIN_DOMAIN; +} + +// Get city data based on domain +function getCityByDomain(domain) { + return cityData.find(city => city.domain === domain); +} + +// Get state name by province_id +function getStateById(provinceId) { + return stateData.find(state => state.id === provinceId)?.name || ''; +} + +// Generate static pages URLs +function getStaticPages(baseUrl) { + return [ + { + url: baseUrl, + lastModified: new Date(), + changeFrequency: 'daily', + priority: 1, + }, + { + url: `${baseUrl}/about-us`, + lastModified: new Date(), + changeFrequency: 'monthly', + priority: 0.8, + }, + { + url: `${baseUrl}/contact-us`, + lastModified: new Date(), + changeFrequency: 'monthly', + priority: 0.8, + }, + { + url: `${baseUrl}/blogs`, + lastModified: new Date(), + changeFrequency: 'weekly', + priority: 0.9, + }, + { + url: `${baseUrl}/doctors`, + lastModified: new Date(), + changeFrequency: 'daily', + priority: 0.9, + }, + { + url: `${baseUrl}/clinics`, + lastModified: new Date(), + changeFrequency: 'daily', + priority: 0.9, + }, + { + url: `${baseUrl}/specialties`, + lastModified: new Date(), + changeFrequency: 'weekly', + priority: 0.9, + }, + ]; +} + +// Generate doctor search URLs based on domain +function getDoctorSearchUrls(domain, baseUrl) { + const urls = []; + + if (isMainDomain(domain)) { + // For main domain, include all cities and limited specialties + cityData.forEach(city => { + const stateName = getStateById(city.province_id); + if (stateName) { + // City-only search + const cityUrl = createSitemapUrl(baseUrl, '/doctors', { + city: city.name, + state: stateName + }); + urls.push(createSitemapEntry(cityUrl, 0.8)); + + // City + specialty combinations (limited to prevent too many URLs) + const limitedSpecialties = limitArray(specialtyData, DOMAIN_CONFIG.MAX_SPECIALTY_COMBINATIONS); + limitedSpecialties.forEach(specialty => { + const specialtyUrl = createSitemapUrl(baseUrl, '/doctors', { + specialty: specialty.name, + city: city.name, + state: stateName + }); + urls.push(createSitemapEntry(specialtyUrl, 0.7)); + }); + } + }); + + // Specialty-only searches + specialtyData.forEach(specialty => { + const specialtyUrl = createSitemapUrl(baseUrl, '/doctors', { + specialty: specialty.name + }); + urls.push(createSitemapEntry(specialtyUrl, 0.8)); + }); + } else { + // For city-specific domains, only include that city's data + const currentCity = getCityByDomain(domain); + if (currentCity) { + const stateName = getStateById(currentCity.province_id); + if (stateName) { + // City-only search + const cityUrl = createSitemapUrl(baseUrl, '/doctors', { + city: currentCity.name, + state: stateName + }); + urls.push(createSitemapEntry(cityUrl, 0.8)); + + // City + specialty combinations + specialtyData.forEach(specialty => { + const specialtyUrl = createSitemapUrl(baseUrl, '/doctors', { + specialty: specialty.name, + city: currentCity.name, + state: stateName + }); + urls.push(createSitemapEntry(specialtyUrl, 0.7)); + }); + } + } + } + + return urls; +} + +// Generate clinic search URLs +function getClinicSearchUrls(domain, baseUrl) { + const urls = []; + + if (isMainDomain(domain)) { + // For main domain, include all cities + cityData.forEach(city => { + const stateName = getStateById(city.province_id); + if (stateName) { + const clinicUrl = createSitemapUrl(baseUrl, '/clinics', { + city: city.name, + state: stateName + }); + urls.push(createSitemapEntry(clinicUrl, 0.8)); + } + }); + } else { + // For city-specific domains, only include that city + const currentCity = getCityByDomain(domain); + if (currentCity) { + const stateName = getStateById(currentCity.province_id); + if (stateName) { + const clinicUrl = createSitemapUrl(baseUrl, '/clinics', { + city: currentCity.name, + state: stateName + }); + urls.push(createSitemapEntry(clinicUrl, 0.8)); + } + } + } + + return urls; +} + +// Generate specialty pages URLs +function getSpecialtyUrls(domain, baseUrl) { + const urls = []; + + if (isMainDomain(domain)) { + // For main domain, include all specialties with main cities only (to prevent too many URLs) + const mainCities = cityData.filter(city => DOMAIN_CONFIG.MAIN_CITIES.includes(city.id)); + + specialtyData.forEach(specialty => { + // Base specialty page + const specialtyUrl = createSitemapUrl(baseUrl, `/specialties/${encodeURIComponent(specialty.name)}`); + urls.push(createSitemapEntry(specialtyUrl, 0.8)); + + // Specialty + city combinations (only for main cities) + mainCities.forEach(city => { + const stateName = getStateById(city.province_id); + if (stateName) { + const citySpecialtyUrl = createSitemapUrl(baseUrl, `/specialties/${encodeURIComponent(specialty.name)}`, { + city: city.name, + state: stateName + }); + urls.push(createSitemapEntry(citySpecialtyUrl, 0.7)); + } + }); + }); + } else { + // For city-specific domains, include specialties with that city only + const currentCity = getCityByDomain(domain); + if (currentCity) { + const stateName = getStateById(currentCity.province_id); + if (stateName) { + specialtyData.forEach(specialty => { + const specialtyUrl = createSitemapUrl(baseUrl, `/specialties/${encodeURIComponent(specialty.name)}`, { + city: currentCity.name, + state: stateName + }); + urls.push(createSitemapEntry(specialtyUrl, 0.7)); + }); + } + } + } + + return urls; +} + +export default async function sitemap() { + try { + const domain = getCurrentDomain(); + const baseUrl = getBaseUrl(domain); + + // Get all URLs + const staticPages = getStaticPages(baseUrl); + const doctorSearchUrls = getDoctorSearchUrls(domain, baseUrl); + const clinicSearchUrls = getClinicSearchUrls(domain, baseUrl); + const specialtyUrls = getSpecialtyUrls(domain, baseUrl); + + // Combine all URLs + const allUrls = [ + ...staticPages, + ...doctorSearchUrls, + ...clinicSearchUrls, + ...specialtyUrls, + ]; + + // Remove duplicates based on URL + const uniqueUrls = allUrls.filter((item, index, arr) => + arr.findIndex(i => i.url === item.url) === index + ); + + return uniqueUrls; + } catch (error) { + console.error('Error generating sitemap:', error); + return []; + } +} \ No newline at end of file diff --git a/utils/sitemap.js b/utils/sitemap.js new file mode 100644 index 0000000..bc74e98 --- /dev/null +++ b/utils/sitemap.js @@ -0,0 +1,45 @@ +// Utility functions for sitemap generation +export const DOMAIN_CONFIG = { + MAIN_DOMAIN: 'nobat724.com', + MAX_SPECIALTY_COMBINATIONS: 20, // Limit specialty combinations to prevent too many URLs + MAIN_CITIES: ['108', '104', '111', '117', '113'], // Tehran, Isfahan, Mashhad, Shiraz, Ahvaz +}; + +export function isMainDomain(domain) { + return domain === DOMAIN_CONFIG.MAIN_DOMAIN; +} + +export function encodeUrlParam(param) { + return encodeURIComponent(param || ''); +} + +export function createSitemapUrl(baseUrl, path, params = {}) { + let url = `${baseUrl}${path}`; + const searchParams = new URLSearchParams(); + + Object.entries(params).forEach(([key, value]) => { + if (value) { + searchParams.append(key, value); + } + }); + + const queryString = searchParams.toString(); + return queryString ? `${url}?${queryString}` : url; +} + +export function createSitemapEntry(url, priority = 0.8, changeFrequency = 'weekly') { + return { + url, + lastModified: new Date(), + changeFrequency, + priority, + }; +} + +export function limitArray(array, limit) { + return limit > 0 ? array.slice(0, limit) : array; +} + +export function getBaseUrl(domain) { + return `https://${domain}`; +} \ No newline at end of file