{{-- OG locale mapping --}} @php $ogLocaleMap = [ 'fr' => 'fr_FR', 'en' => 'en_US', 'it' => 'it_IT', 'ar' => 'ar_SA', 'de' => 'de_DE', 'es' => 'es_ES', 'pt' => 'pt_BR', 'ru' => 'ru_RU', ]; @endphp {{-- Hreflang tags --}} @if(!empty($localeUrls)) @php $pageSuffix = (!empty($currentPage) && $currentPage > 1) ? '/' . $currentPage : ''; @endphp @foreach($localeUrls as $code => $path) @endforeach @endif {{-- Canonical URL --}} @php $canonicalUrl = url()->current(); @endphp {{-- Rel prev/next for split posts --}} @if(!empty($totalPages) && $totalPages > 1) @php $baseUrl = (!empty($post) && !empty($locale)) ? route('content.show', ['locale' => $locale, 'slug' => $post->translation($locale)?->slug]) : url()->current(); @endphp @if($currentPage > 1) @endif @if($currentPage < $totalPages) @endif @endif {{-- Open Graph meta tags --}} @php $ogTitle = ''; $ogDescription = ''; $ogImage = ''; $ogType = 'website'; $ogLocale = $locale ?? 'fr'; $ogLocaleFormatted = $ogLocaleMap[$ogLocale] ?? $ogLocale; if (!empty($post)) { $ogTrans = $post->translation($ogLocale); $ogTitle = $ogTrans?->meta_title ?: $ogTrans?->title ?: ''; $ogDescription = $ogTrans?->meta_description ?: Str::limit(strip_tags($ogTrans?->body ?? ''), 200); // Enrich for subpages if (!empty($currentPage) && $currentPage > 1 && !empty($totalPages) && !empty($globalToc[$currentPage - 1]['title'])) { $chapterTitle = $globalToc[$currentPage - 1]['title']; $ogTitle = $ogTitle . ' - ' . $chapterTitle . ' (' . $currentPage . '/' . $totalPages . ')'; $ogDescription = Str::limit(strip_tags($pageBody ?? ''), 200); } $ogImage = $ogTrans?->og_image ?? ''; $ogType = $post->isPage() ? 'website' : 'article'; } elseif (!empty($category)) { $catTrans = $category->translation($ogLocale); $ogTitle = $catTrans?->name ?? ''; $ogDescription = $catTrans?->description ?? ''; } if (empty($ogTitle)) { $ogTitle = config('app.name', 'Pierre2.net'); } @endphp @if($ogDescription) @endif @if($ogImage) @endif @if(!empty($localeUrls)) @foreach($localeUrls as $code => $path) @if($code !== $ogLocale) @endif @endforeach @endif {{-- Twitter Card meta tags --}} @if($ogDescription) @endif @if($ogImage) @endif {{-- Article timestamps --}} @if(!empty($post) && !$post->isPage()) @if($post->updated_at) @endif @endif {{-- JSON-LD Structured Data --}} @php $siteName = 'Pierre2.net'; $siteUrl = rtrim(config('app.url'), '/'); $jsonLdScripts = []; // WebSite schema (all pages) $webSiteSchema = [ '@context' => 'https://schema.org', '@type' => 'WebSite', 'name' => $siteName, 'url' => $siteUrl, ]; $webSiteSchema['potentialAction'] = [ [ '@type' => 'SearchAction', 'target' => [ '@type' => 'EntryPoint', 'urlTemplate' => $siteUrl . '/' . $ogLocale . '/search?q={search_term_string}', ], 'query-input' => [ '@type' => 'PropertyValueSpecification', 'valueRequired' => true, 'valueName' => 'search_term_string', ], ], ]; $jsonLdScripts[] = $webSiteSchema; // WebPage schema (all pages) $webPageSchema = [ '@context' => 'https://schema.org', '@type' => 'WebPage', 'name' => $ogTitle, 'url' => $canonicalUrl, 'inLanguage' => $ogLocale, ]; if ($ogDescription) { $webPageSchema['description'] = $ogDescription; } $jsonLdScripts[] = $webPageSchema; // Article + Person + BreadcrumbList for posts if (!empty($post) && !$post->isPage()) { $articleTrans = $post->translation($ogLocale); $articleSchema = [ '@context' => 'https://schema.org', '@type' => 'Article', 'headline' => $articleTrans?->title ?? $ogTitle, 'url' => $canonicalUrl, 'inLanguage' => $ogLocale, ]; if ($post->published_at) { $articleSchema['datePublished'] = $post->published_at->toIso8601String(); } elseif ($post->created_at) { $articleSchema['datePublished'] = $post->created_at->toIso8601String(); } if ($post->updated_at) { $articleSchema['dateModified'] = $post->updated_at->toIso8601String(); } if ($ogImage) { $articleSchema['image'] = Str::startsWith($ogImage, 'http') ? $ogImage : asset('storage/' . $ogImage); } // Author $author = $post->author; if ($author) { $personSchema = [ '@type' => 'Person', 'name' => $author->name, ]; $articleSchema['author'] = $personSchema; } // Word count $wordCount = str_word_count(strip_tags($articleTrans?->body ?? '')); if ($wordCount > 0) { $articleSchema['wordCount'] = $wordCount; } // Article section (category) if ($post->relationLoaded('categories') && $post->categories->isNotEmpty()) { $catName = $post->categories->first()->translation($ogLocale)?->name; if ($catName) { $articleSchema['articleSection'] = $catName; } } // Keywords from tags if ($post->relationLoaded('tags') && $post->tags->isNotEmpty()) { $keywords = $post->tags ->map(fn ($tag) => $tag->translation($ogLocale)?->name) ->filter() ->values() ->all(); if ($keywords) { $articleSchema['keywords'] = implode(', ', $keywords); } } $jsonLdScripts[] = $articleSchema; // BreadcrumbList $breadcrumbItems = [ [ '@type' => 'ListItem', 'position' => 1, 'name' => $siteName, 'item' => $siteUrl . '/' . $ogLocale, ], ]; // Add category if available if ($post->relationLoaded('categories') && $post->categories->isNotEmpty()) { $firstCat = $post->categories->first(); $catTranslation = $firstCat->translation($ogLocale); if ($catTranslation && $catTranslation->slug) { $breadcrumbItems[] = [ '@type' => 'ListItem', 'position' => 2, 'name' => $catTranslation->name, 'item' => $siteUrl . '/' . $ogLocale . '/category/' . $catTranslation->slug, ]; } } $breadcrumbItems[] = [ '@type' => 'ListItem', 'position' => count($breadcrumbItems) + 1, 'name' => $articleTrans?->title ?? $ogTitle, ]; $jsonLdScripts[] = [ '@context' => 'https://schema.org', '@type' => 'BreadcrumbList', 'itemListElement' => $breadcrumbItems, ]; } // BreadcrumbList for category pages if (!empty($category)) { $catTransBc = $category->translation($ogLocale); $jsonLdScripts[] = [ '@context' => 'https://schema.org', '@type' => 'BreadcrumbList', 'itemListElement' => [ [ '@type' => 'ListItem', 'position' => 1, 'name' => $siteName, 'item' => $siteUrl . '/' . $ogLocale, ], [ '@type' => 'ListItem', 'position' => 2, 'name' => $catTransBc?->name ?? '', ], ], ]; } @endphp @foreach($jsonLdScripts as $schema) @endforeach