feat(seo): complete OG/Twitter/structured-data coverage + clean encoding
Blog list (/blog): add robots, full Open Graph + Twitter, Blog + BreadcrumbList JSON-LD, per-page self-canonical, and rel=prev/next for paginated pages. Blog post: add robots, og:site_name, article:published_time / modified_time / author / section, twitter:image, og:image:alt, and a BreadcrumbList JSON-LD (Home → Blog → Category → Post). Gallery (/gallery): add robots, full OG + Twitter (with first image as og:image), ImageGallery + BreadcrumbList JSON-LD. Encoding: register HtmlEncoder.Create(UnicodeRanges.All) so Persian text in meta tags and JSON-LD renders literally instead of &#xXXXX; entities (smaller, cleaner output; friendlier to SEO validators). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,58 @@
|
||||
@page "/blog"
|
||||
@model DrSousan.Api.Pages.Blog.BlogIndexModel
|
||||
@{
|
||||
var blogBase = Environment.GetEnvironmentVariable("SITE_BASE_URL")?.TrimEnd('/') ?? (Request.Scheme + "://" + Request.Host);
|
||||
var catQs = string.IsNullOrEmpty(Model.ActiveCat) ? "" : "&category=" + Model.ActiveCat;
|
||||
string PageUrl(int p) => p <= 1
|
||||
? blogBase + "/blog" + (string.IsNullOrEmpty(Model.ActiveCat) ? "" : "?category=" + Model.ActiveCat)
|
||||
: blogBase + "/blog?pg=" + p + catQs;
|
||||
var blogDesc = "مقالات تخصصی دکتر سوسن آلطه درباره زیبایی پوست، بوتاکس، فیلر، لیزر و مراقبت از پوست.";
|
||||
}
|
||||
|
||||
@section Head {
|
||||
<title>@ViewData["Title"]</title>
|
||||
<meta name="description" content="مقالات تخصصی دکتر سوسن آلطه درباره زیبایی پوست، بوتاکس، فیلر، لیزر و مراقبت از پوست." />
|
||||
<link rel="canonical" href="@((Environment.GetEnvironmentVariable("SITE_BASE_URL")?.TrimEnd('/') ?? (Request.Scheme + "://" + Request.Host)) + "/blog")" />
|
||||
<meta name="description" content="@blogDesc" />
|
||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1" />
|
||||
<meta name="author" content="@ViewData["SiteName"]" />
|
||||
<meta name="theme-color" content="#B8955A" />
|
||||
<link rel="canonical" href="@PageUrl(Model.CurrentPage)" />
|
||||
@if (Model.CurrentPage > 1) { <link rel="prev" href="@PageUrl(Model.CurrentPage - 1)" /> }
|
||||
@if (Model.CurrentPage < Model.TotalPages) { <link rel="next" href="@PageUrl(Model.CurrentPage + 1)" /> }
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="@ViewData["SiteName"]" />
|
||||
<meta property="og:title" content="@ViewData["Title"]" />
|
||||
<meta property="og:description" content="@blogDesc" />
|
||||
<meta property="og:url" content="@PageUrl(Model.CurrentPage)" />
|
||||
<meta property="og:locale" content="fa_IR" />
|
||||
<!-- Twitter -->
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:title" content="@ViewData["Title"]" />
|
||||
<meta name="twitter:description" content="@blogDesc" />
|
||||
|
||||
<!-- Structured data: Blog + breadcrumb -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@@context": "https://schema.org",
|
||||
"@@type": "Blog",
|
||||
"name": "@ViewData["Title"]",
|
||||
"description": "@blogDesc",
|
||||
"url": "@(blogBase)/blog",
|
||||
"inLanguage": "fa-IR",
|
||||
"publisher": { "@@type": "Organization", "name": "@ViewData["SiteName"]", "url": "@blogBase" }
|
||||
}
|
||||
</script>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@@context": "https://schema.org",
|
||||
"@@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{ "@@type": "ListItem", "position": 1, "name": "خانه", "item": "@blogBase/" },
|
||||
{ "@@type": "ListItem", "position": 2, "name": "وبلاگ", "item": "@blogBase/blog" }
|
||||
]
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
/* ─── Blog Hero ─────────────────────────────────────────────── */
|
||||
.blog-hero{background:linear-gradient(135deg,var(--gold-pale) 0%,#EDE0CA 100%);padding:6rem 2rem 3rem;text-align:center}
|
||||
|
||||
Reference in New Issue
Block a user