Initial baseline: LaraBlog core with plugin commerce surface.
Captures the current working tree after theme slots, ArticleAccess, and the payment / paid-content plugins so subsequent work has a reviewable git history.
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Domain\Seo;
|
||||
|
||||
use App\Models\Article;
|
||||
use App\Settings\GeneralSettings;
|
||||
use App\Settings\SeoSettings;
|
||||
|
||||
class SeoPresenter
|
||||
{
|
||||
public function __construct(
|
||||
protected GeneralSettings $generalSettings,
|
||||
protected SeoSettings $seoSettings,
|
||||
) {}
|
||||
|
||||
public function title(?string $title = null): string
|
||||
{
|
||||
$suffix = $this->seoSettings->meta_title_suffix;
|
||||
|
||||
if ($title === null || $title === '') {
|
||||
return $this->generalSettings->site_name;
|
||||
}
|
||||
|
||||
return $suffix
|
||||
? "{$title} {$suffix}"
|
||||
: "{$title} - {$this->generalSettings->site_name}";
|
||||
}
|
||||
|
||||
public function description(?string $description = null): string
|
||||
{
|
||||
return $description
|
||||
?: ($this->seoSettings->default_description
|
||||
?: ($this->generalSettings->site_description ?? ''));
|
||||
}
|
||||
|
||||
public function keywords(?string $keywords = null): ?string
|
||||
{
|
||||
return $keywords ?: $this->seoSettings->default_keywords;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{title: string, description: string, keywords: ?string, canonical: string, og: array<string, string>, twitter: array<string, string>, jsonld: array<string, mixed>}
|
||||
*/
|
||||
public function forHome(): array
|
||||
{
|
||||
$canonical = rtrim($this->generalSettings->site_url ?: url('/'), '/') ?: url('/');
|
||||
|
||||
return [
|
||||
'title' => $this->title(),
|
||||
'description' => $this->description(),
|
||||
'keywords' => $this->keywords(),
|
||||
'canonical' => $canonical,
|
||||
'og' => $this->openGraph(),
|
||||
'twitter' => $this->twitterCards(),
|
||||
'jsonld' => $this->jsonLd(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{title: string, description: string, keywords: ?string, canonical: string, og: array<string, string>, twitter: array<string, string>, jsonld: array<string, mixed>}
|
||||
*/
|
||||
public function forArticle(Article $article): array
|
||||
{
|
||||
$canonical = url('/show-'.$article->id.'.shtml');
|
||||
|
||||
return [
|
||||
'title' => $this->title($article->title),
|
||||
'description' => $this->description($article->description),
|
||||
'keywords' => $this->keywords($article->keywords),
|
||||
'canonical' => $canonical,
|
||||
'og' => $this->openGraph($article),
|
||||
'twitter' => $this->twitterCards($article),
|
||||
'jsonld' => $this->jsonLd($article),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function openGraph(?Article $article = null): array
|
||||
{
|
||||
$title = $this->title($article?->title);
|
||||
$description = $this->description($article?->description);
|
||||
$url = $article
|
||||
? url('/show-'.$article->id.'.shtml')
|
||||
: ($this->generalSettings->site_url ?: url('/'));
|
||||
|
||||
return array_filter([
|
||||
'og:title' => $title,
|
||||
'og:description' => $description,
|
||||
'og:url' => $url,
|
||||
'og:type' => $article ? 'article' : 'website',
|
||||
'og:site_name' => $this->generalSettings->site_name,
|
||||
'og:locale' => 'zh_CN',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function twitterCards(?Article $article = null): array
|
||||
{
|
||||
return array_filter([
|
||||
'twitter:card' => 'summary',
|
||||
'twitter:title' => $this->title($article?->title),
|
||||
'twitter:description' => $this->description($article?->description),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function jsonLd(?Article $article = null): array
|
||||
{
|
||||
if (! $this->seoSettings->json_ld_enabled) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($article === null) {
|
||||
return [
|
||||
'@context' => 'https://schema.org',
|
||||
'@type' => 'WebSite',
|
||||
'name' => $this->generalSettings->site_name,
|
||||
'url' => $this->generalSettings->site_url ?: url('/'),
|
||||
'description' => $this->description(),
|
||||
'potentialAction' => [
|
||||
'@type' => 'SearchAction',
|
||||
'target' => url('/search.shtml').'?keywords={search_term_string}',
|
||||
'query-input' => 'required name=search_term_string',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'@context' => 'https://schema.org',
|
||||
'@type' => 'BlogPosting',
|
||||
'headline' => $article->title,
|
||||
'description' => $this->description($article->description),
|
||||
'datePublished' => optional($article->published_at)?->toIso8601String(),
|
||||
'dateModified' => optional($article->updated_at)?->toIso8601String(),
|
||||
'author' => [
|
||||
'@type' => 'Person',
|
||||
'name' => $article->user?->name ?? $article->user?->username,
|
||||
],
|
||||
'mainEntityOfPage' => url('/show-'.$article->id.'.shtml'),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user