feat: add Schema.org structured data to blog index and post pages

This commit is contained in:
Ümit Tunç
2026-05-25 06:48:14 +03:00
parent c1dc4629c0
commit f69e7bae7b
2 changed files with 332 additions and 0 deletions
+167
View File
@@ -217,6 +217,173 @@
</div>
</section>
@push('structured-data')
@php
$siteName = setting('site_name', 'Trunçgil Teknoloji');
$siteLogo = setting('site_logo') ? (str_starts_with(setting('site_logo'), 'http') ? setting('site_logo') : asset('storage/' . ltrim(setting('site_logo'), '/'))) : asset('assets/img/logo.png');
$sitePhone = setting('contact_phone', '+902244431620');
$siteEmail = setting('contact_email', 'info@truncgil.com');
$siteAddress = setting('contact_address', 'Gaziantep Teknopark, Şahinbey, Gaziantep');
$socialLinksRaw = setting('social_links');
$socialLinks = [];
if ($socialLinksRaw) {
$decoded = json_decode($socialLinksRaw, true);
if (is_array($decoded)) {
$socialLinks = array_values(array_filter($decoded));
} elseif (is_string($socialLinksRaw)) {
$socialLinks = [$socialLinksRaw];
}
}
if (empty($socialLinks)) {
$socialLinks = [
'https://twitter.com/truncgil',
'https://facebook.com/truncgil',
'https://instagram.com/truncgil',
'https://youtube.com/truncgil',
'https://linkedin.com/company/truncgil'
];
}
// 1. Organization & LocalBusiness combined
$publisherData = [
"@context" => "https://schema.org",
"@type" => "ProfessionalService",
"@id" => url('/') . "#organization",
"name" => $siteName,
"url" => url('/'),
"logo" => [
"@type" => "ImageObject",
"url" => $siteLogo
],
"image" => $siteLogo,
"telephone" => $sitePhone,
"email" => $siteEmail,
"address" => [
"@type" => "PostalAddress",
"streetAddress" => $siteAddress,
"addressLocality" => "Şahinbey",
"addressRegion" => "Gaziantep",
"postalCode" => "27010",
"addressCountry" => "TR"
],
"geo" => [
"@type" => "GeoCoordinates",
"latitude" => 37.0274446,
"longitude" => 37.3074315
],
"hasMap" => "https://maps.google.com/?q=37.0274446,37.3074315",
"sameAs" => $socialLinks,
"areaServed" => [
["@type" => "Country", "name" => "TR"],
["@type" => "Country", "name" => "DE"],
["@type" => "Country", "name" => "RU"],
["@type" => "Country", "name" => "US"],
["@type" => "AdministrativeArea", "name" => "Gaziantep"],
["@type" => "AdministrativeArea", "name" => "Bursa"]
],
"priceRange" => "$$"
];
// 2. Breadcrumbs
$activeCategorySlug = request()->query('category');
$activeCategory = null;
if ($activeCategorySlug && isset($sidebarCategories)) {
$activeCategory = $sidebarCategories->firstWhere('slug', $activeCategorySlug);
}
if (!$activeCategory && $activeCategorySlug && isset($highlightCategories)) {
$activeCategory = $highlightCategories->firstWhere('slug', $activeCategorySlug);
}
$activeCategoryName = $activeCategory ? $activeCategory->name : null;
$breadcrumbList = [
[
"@type" => "ListItem",
"position" => 1,
"name" => "Anasayfa",
"item" => url('/')
],
[
"@type" => "ListItem",
"position" => 2,
"name" => "Blog",
"item" => route('blog.index')
]
];
if ($activeCategorySlug && $activeCategoryName) {
$breadcrumbList[] = [
"@type" => "ListItem",
"position" => 3,
"name" => $activeCategoryName,
"item" => route('blog.index', ['category' => $activeCategorySlug])
];
}
$breadcrumbs = [
"@context" => "https://schema.org",
"@type" => "BreadcrumbList",
"itemListElement" => $breadcrumbList
];
// 3. Blog List & Posts
$blogPostsList = [];
if (isset($posts) && count($posts) > 0) {
foreach ($posts as $p) {
$pTitle = method_exists($p, 'translate') ? $p->translate('title') : $p->title;
$pExcerpt = method_exists($p, 'translate') ? $p->translate('excerpt') : ($p->excerpt ?? '');
$pContent = method_exists($p, 'translate') ? $p->translate('content') : ($p->content ?? '');
$pExcerptText = trim(strip_tags($pExcerpt));
if (empty($pExcerptText)) {
$pExcerptText = \Illuminate\Support\Str::limit(trim(strip_tags($pContent)), 160);
}
$pUrl = route('blog.show', $p->slug);
$pImageUrl = $p->featured_image ? asset('storage/' . $p->featured_image) : ($p->featured_image_url ?? asset('assets/img/photos/tb10.jpg'));
$blogPostsList[] = [
"@type" => "BlogPosting",
"headline" => $pTitle,
"description" => $pExcerptText,
"image" => $pImageUrl,
"url" => $pUrl,
"datePublished" => $p->published_at ? $p->published_at->toIso8601String() : $p->created_at->toIso8601String(),
"author" => [
"@type" => "Person",
"name" => $p->author ? $p->author->name : 'Trunçgil'
]
];
}
}
$blogSchema = [
"@context" => "https://schema.org",
"@type" => "Blog",
"@id" => route('blog.index') . "#blog",
"name" => $siteName . " Blog",
"description" => "Merhaba! Biz Trunçgil. Blogumuza hoş geldiniz. Burada web tasarım, yazılım geliştirme ve teknolojik yeniliklere dair ipuçlarını ve deneyimlerimizi paylaşıyoruz.",
"url" => route('blog.index'),
"publisher" => [
"@type" => "Organization",
"name" => $siteName,
"logo" => [
"@type" => "ImageObject",
"url" => $siteLogo
]
],
"blogPost" => $blogPostsList
];
@endphp
<script type="application/ld+json">
{!! json_encode($publisherData, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) !!}
</script>
<script type="application/ld+json">
{!! json_encode($breadcrumbs, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) !!}
</script>
<script type="application/ld+json">
{!! json_encode($blogSchema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) !!}
</script>
@endpush
@push('styles')
<style>
/* Ensure uniform layout and clamping for title and excerpt */
+165
View File
@@ -165,6 +165,171 @@
</section>
@endsection
@push('structured-data')
@php
$postTitle = method_exists($post, 'translate') ? $post->translate('title') : $post->title;
$postExcerpt = method_exists($post, 'translate') ? $post->translate('excerpt') : ($post->excerpt ?? '');
$postContent = method_exists($post, 'translate') ? $post->translate('content') : ($post->content ?? '');
$postExcerptText = trim(strip_tags($postExcerpt));
if (empty($postExcerptText)) {
$postExcerptText = \Illuminate\Support\Str::limit(trim(strip_tags($postContent)), 160);
}
$postUrl = route('blog.show', $post->slug);
$imageUrl = $post->featured_image ? asset('storage/' . $post->featured_image) : ($post->featured_image_url ?? asset('assets/img/photos/tb10.jpg'));
$publishedDate = $post->published_at ? $post->published_at->toIso8601String() : $post->created_at->toIso8601String();
$modifiedDate = $post->updated_at ? $post->updated_at->toIso8601String() : $publishedDate;
$authorName = $post->author ? $post->author->name : 'Trunçgil';
$authorRole = $post->author && $post->author->role ? $post->author->role : 'Trunçgil Teknoloji Editörü';
$authorUrl = route('blog.index', ['author' => $post->author_id ?? 1]);
$siteName = setting('site_name', 'Trunçgil Teknoloji');
$siteLogo = setting('site_logo') ? (str_starts_with(setting('site_logo'), 'http') ? setting('site_logo') : asset('storage/' . ltrim(setting('site_logo'), '/'))) : asset('assets/img/logo.png');
$sitePhone = setting('contact_phone', '+902244431620');
$siteEmail = setting('contact_email', 'info@truncgil.com');
$siteAddress = setting('contact_address', 'Gaziantep Teknopark, Şahinbey, Gaziantep');
$socialLinksRaw = setting('social_links');
$socialLinks = [];
if ($socialLinksRaw) {
$decoded = json_decode($socialLinksRaw, true);
if (is_array($decoded)) {
$socialLinks = array_values(array_filter($decoded));
} elseif (is_string($socialLinksRaw)) {
$socialLinks = [$socialLinksRaw];
}
}
if (empty($socialLinks)) {
$socialLinks = [
'https://twitter.com/truncgil',
'https://facebook.com/truncgil',
'https://instagram.com/truncgil',
'https://youtube.com/truncgil',
'https://linkedin.com/company/truncgil'
];
}
// 1. Organization & LocalBusiness combined
$publisherData = [
"@context" => "https://schema.org",
"@type" => "ProfessionalService",
"@id" => url('/') . "#organization",
"name" => $siteName,
"url" => url('/'),
"logo" => [
"@type" => "ImageObject",
"url" => $siteLogo
],
"image" => $siteLogo,
"telephone" => $sitePhone,
"email" => $siteEmail,
"address" => [
"@type" => "PostalAddress",
"streetAddress" => $siteAddress,
"addressLocality" => "Şahinbey",
"addressRegion" => "Gaziantep",
"postalCode" => "27010",
"addressCountry" => "TR"
],
"geo" => [
"@type" => "GeoCoordinates",
"latitude" => 37.0274446,
"longitude" => 37.3074315
],
"hasMap" => "https://maps.google.com/?q=37.0274446,37.3074315",
"sameAs" => $socialLinks,
"areaServed" => [
["@type" => "Country", "name" => "TR"],
["@type" => "Country", "name" => "DE"],
["@type" => "Country", "name" => "RU"],
["@type" => "Country", "name" => "US"],
["@type" => "AdministrativeArea", "name" => "Gaziantep"],
["@type" => "AdministrativeArea", "name" => "Bursa"]
],
"priceRange" => "$$"
];
// 2. BreadcrumbList
$categoryName = $post->category ? $post->category->name : 'Genel';
$categorySlug = $post->category ? $post->category->slug : 'genel';
$categoryUrl = route('blog.index', ['category' => $categorySlug]);
$breadcrumbs = [
"@context" => "https://schema.org",
"@type" => "BreadcrumbList",
"itemListElement" => [
[
"@type" => "ListItem",
"position" => 1,
"name" => "Anasayfa",
"item" => url('/')
],
[
"@type" => "ListItem",
"position" => 2,
"name" => "Blog",
"item" => route('blog.index')
],
[
"@type" => "ListItem",
"position" => 3,
"name" => $categoryName,
"item" => $categoryUrl
],
[
"@type" => "ListItem",
"position" => 4,
"name" => $postTitle,
"item" => $postUrl
]
]
];
// 3. BlogPosting
$blogPosting = [
"@context" => "https://schema.org",
"@type" => "BlogPosting",
"@id" => $postUrl . "#blogposting",
"mainEntityOfPage" => [
"@type" => "WebPage",
"@id" => $postUrl
],
"headline" => $postTitle,
"description" => $postExcerptText,
"image" => $imageUrl,
"datePublished" => $publishedDate,
"dateModified" => $modifiedDate,
"author" => [
"@type" => "Person",
"name" => $authorName,
"jobTitle" => $authorRole,
"url" => $authorUrl
],
"publisher" => [
"@type" => "Organization",
"name" => $siteName,
"logo" => [
"@type" => "ImageObject",
"url" => $siteLogo
]
],
"articleSection" => $categoryName,
"keywords" => is_array($post->tags) ? implode(', ', $post->tags) : ($post->tags ?? '')
];
@endphp
<script type="application/ld+json">
{!! json_encode($publisherData, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) !!}
</script>
<script type="application/ld+json">
{!! json_encode($breadcrumbs, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) !!}
</script>
<script type="application/ld+json">
{!! json_encode($blogPosting, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) !!}
</script>
@endpush
@push('styles')
<!-- CodeMirror Styles -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.13/codemirror.min.css" integrity="sha384-zaeBlB/vwYsDRSlFajnDd7OydJ0cWk+c2OWybl3eSUf6hW2EbhlCsQPqKr3gkznT" crossorigin="anonymous">