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 */ 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 */ 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'); } }