From 6af6a026a130827dff335a528acaf73928009db2 Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Sun, 7 Jun 2026 08:16:30 +0330 Subject: [PATCH] [SEO] JobPosting structured data, canonical/OG meta, noindex private pages, fuller sitemap Strategy = Google-for-Jobs + clean indexing. Add schema.org JobPosting JSON-LD to shift & job detail pages (title, description, datePosted, validThrough, employmentType, hiringOrganization, jobLocation, baseSalary) plus Organization + WebSite JSON-LD on the home page (SeoJsonLd helper; System.Text.Json => valid, script-safe). Layout emits per-page canonical, Open Graph + Twitter cards, and applies robots noindex,nofollow to all private/applicant areas (/Admin,/Me,/Employer,/Account,/Preferences) so applicant data is never indexed. robots.txt now disallows those + /resume,/avatar,/report,/push,/notifications and points at the sitemap; sitemap.xml adds facility pages + content pages (Download/Help/Privacy/Rules/Terms). Co-Authored-By: Claude Opus 4.8 --- src/JobsMedical.Web/Pages/Index.cshtml | 6 + src/JobsMedical.Web/Pages/Jobs/Details.cshtml | 5 + .../Pages/Shared/_Layout.cshtml | 37 ++++- .../Pages/Shifts/Details.cshtml | 5 + src/JobsMedical.Web/Program.cs | 17 ++- src/JobsMedical.Web/Services/SeoJsonLd.cs | 127 ++++++++++++++++++ 6 files changed, 194 insertions(+), 3 deletions(-) create mode 100644 src/JobsMedical.Web/Services/SeoJsonLd.cs diff --git a/src/JobsMedical.Web/Pages/Index.cshtml b/src/JobsMedical.Web/Pages/Index.cshtml index bead6b6..06aa80a 100644 --- a/src/JobsMedical.Web/Pages/Index.cshtml +++ b/src/JobsMedical.Web/Pages/Index.cshtml @@ -152,3 +152,9 @@ + +@section Head { + @{ var bu = $"{ViewContext.HttpContext.Request.Scheme}://{ViewContext.HttpContext.Request.Host}"; } + @Html.Raw("") + @Html.Raw("") +} diff --git a/src/JobsMedical.Web/Pages/Jobs/Details.cshtml b/src/JobsMedical.Web/Pages/Jobs/Details.cshtml index 74b3a67..fde4abe 100644 --- a/src/JobsMedical.Web/Pages/Jobs/Details.cshtml +++ b/src/JobsMedical.Web/Pages/Jobs/Details.cshtml @@ -177,3 +177,8 @@ { } + +@section Head { + @{ var bu = $"{ViewContext.HttpContext.Request.Scheme}://{ViewContext.HttpContext.Request.Host}"; } + @Html.Raw("") +} diff --git a/src/JobsMedical.Web/Pages/Shared/_Layout.cshtml b/src/JobsMedical.Web/Pages/Shared/_Layout.cshtml index d05c7cd..c0e552f 100644 --- a/src/JobsMedical.Web/Pages/Shared/_Layout.cshtml +++ b/src/JobsMedical.Web/Pages/Shared/_Layout.cshtml @@ -17,14 +17,46 @@ meHasAvatar = info?.HasAvatar ?? false; } var meInitial = string.IsNullOrWhiteSpace(meName) ? "؟" : meName!.Trim().Substring(0, 1); + + // --- SEO context --- + var baseUrl = $"{Context.Request.Scheme}://{Context.Request.Host}"; + var path = Context.Request.Path.Value ?? "/"; + var canonical = baseUrl + (path == "/" ? "" : path); // canonical ignores query string + var pageDesc = ViewData["Description"] as string + ?? "همکادر؛ سامانه یافتن شیفت و موقعیت استخدامی برای کادر درمان (پزشک، پرستار، ماما و تکنسین) در بیمارستان‌ها و کلینیک‌های تهران."; + var pageTitle = title is null ? "همکادر | شیفت و استخدام کادر درمان" : title + " | همکادر"; + var ogImage = ViewData["OgImage"] as string ?? baseUrl + "/icons/icon-512.png"; + // Private/applicant areas must never be indexed. + string[] noindexPrefixes = { "/Admin", "/Me", "/Employer", "/Account", "/Preferences" }; + var noIndex = (ViewData["NoIndex"] as bool? ?? false) + || noindexPrefixes.Any(p => path.StartsWith(p, StringComparison.OrdinalIgnoreCase)); } - @(title is null ? "همکادر | شیفت و استخدام کادر درمان" : title + " | همکادر") - + @pageTitle + + @if (noIndex) + { + + } + else + { + + } + @* Open Graph / Twitter — rich previews when shared in Telegram/Bale/etc. *@ + + + + + + + + + + @* Preload the body-weight font so the swap from Tahoma happens fast. Vazirmatn is self-hosted under wwwroot/fonts (@@font-face in site.css) — no external CDN. *@ @@ -38,6 +70,7 @@ + @await RenderSectionAsync("Head", required: false)