feat: implement structured data support for blog and page components, enhancing SEO and user experience through JSON-LD integration
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user