Files
citrus/app/Support/BlogStructuredData.php

150 lines
4.8 KiB
PHP

<?php
namespace App\Support;
use App\Models\Blog;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Str;
class BlogStructuredData extends StructuredData
{
public static function forIndex(LengthAwarePaginator $posts, string $pageUrl): array
{
$pageName = __('blog.meta-index-title');
$pageDescription = __('blog.meta-index-description');
$itemListElements = [];
$offset = ($posts->currentPage() - 1) * $posts->perPage();
foreach ($posts as $index => $post) {
$itemListElements[] = self::listItem(
$offset + $index + 1,
self::postSummarySchema($post),
);
}
return self::wrap([
self::websiteNode(),
self::organizationNode(),
self::webPageNode($pageUrl, $pageName, $pageDescription, [
'@type' => 'CollectionPage',
'mainEntity' => ['@id' => $pageUrl . '#itemlist'],
]),
self::breadcrumbNode($pageUrl, [
['name' => __('blog.breadcrumb_home'), 'item' => self::siteUrl()],
['name' => $pageName, 'item' => $pageUrl],
]),
[
'@type' => 'ItemList',
'@id' => $pageUrl . '#itemlist',
'name' => $pageName,
'numberOfItems' => $posts->total(),
'itemListElement' => $itemListElements,
],
]);
}
public static function forShow(Blog $post, string $pageUrl): array
{
$title = $post->translate('title');
$description = Str::limit(strip_tags((string) $post->translate('excerpt')), 160);
$imageUrl = $post->featured_image_url ?: self::defaultImageUrl();
$publishedAt = $post->published_at ?? $post->created_at;
$blogPosting = [
'@type' => 'BlogPosting',
'@id' => $pageUrl . '#article',
'mainEntityOfPage' => ['@id' => $pageUrl . '#webpage'],
'headline' => $title,
'description' => $description,
'image' => [$imageUrl],
'inLanguage' => app()->getLocale(),
'author' => [
'@type' => 'Person',
'name' => $post->author->name ?? __('blog.default_author'),
],
'publisher' => self::publisherNode(),
'datePublished' => $publishedAt->toIso8601String(),
'dateModified' => $post->updated_at->toIso8601String(),
'url' => $pageUrl,
];
$content = strip_tags((string) $post->translate('content'));
if ($content !== '') {
$blogPosting['articleBody'] = Str::limit($content, 5000);
}
return self::wrap([
self::websiteNode(),
self::organizationNode(),
self::webPageNode($pageUrl, $title, $description, [
'mainEntity' => ['@id' => $pageUrl . '#article'],
'dateModified' => $post->updated_at->toIso8601String(),
]),
self::breadcrumbNode($pageUrl, [
['name' => __('blog.breadcrumb_home'), 'item' => self::siteUrl()],
['name' => __('blog.meta-index-title'), 'item' => route('blog.index')],
['name' => $title, 'item' => $pageUrl],
]),
$blogPosting,
]);
}
/**
* @return array<string, mixed>
*/
protected static function postSummarySchema(Blog $post): array
{
$schema = [
'@type' => 'BlogPosting',
'headline' => $post->translate('title'),
'url' => route('blog.show', $post->slug),
];
if ($post->featured_image_url) {
$schema['image'] = [$post->featured_image_url];
}
$publishedAt = $post->published_at ?? $post->created_at;
if ($publishedAt) {
$schema['datePublished'] = $publishedAt->toIso8601String();
}
return $schema;
}
/**
* @return array<string, mixed>
*/
protected static function publisherNode(): array
{
$publisher = [
'@type' => 'Organization',
'@id' => self::siteUrl() . '#organization',
'name' => self::siteName(),
];
$logo = setting('site_logo');
if ($logo) {
$logoUrl = str_starts_with($logo, 'http') ? $logo : asset('storage/' . ltrim($logo, '/'));
$publisher['logo'] = [
'@type' => 'ImageObject',
'url' => $logoUrl,
];
}
return $publisher;
}
protected static function defaultImageUrl(): string
{
$defaultImage = setting('default_meta_image');
if ($defaultImage) {
return str_starts_with($defaultImage, 'http') ? $defaultImage : asset($defaultImage);
}
return asset('assets/img/logo.png');
}
}