Current state with latest updates
This commit is contained in:
@@ -10,6 +10,7 @@ use App\Services\Academy\AcademyAccessService;
|
||||
use App\Services\Academy\AcademyInteractionService;
|
||||
use App\Support\AcademyAnalytics\AcademyAnalyticsContentType;
|
||||
use App\Support\Seo\SeoFactory;
|
||||
use App\Support\Seo\SeoDataBuilder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
use Inertia\Inertia;
|
||||
@@ -44,6 +45,13 @@ final class AcademyPromptPackController extends Controller
|
||||
route('academy.packs.index'),
|
||||
)
|
||||
->toArray();
|
||||
$seo = SeoDataBuilder::fromArray($seo)
|
||||
->breadcrumbs([
|
||||
['name' => 'Academy', 'url' => route('academy.index')],
|
||||
['name' => 'Prompt Packs', 'url' => route('academy.packs.index')],
|
||||
])
|
||||
->build()
|
||||
->toArray();
|
||||
|
||||
return Inertia::render('Academy/List', [
|
||||
'pageType' => 'packs',
|
||||
@@ -79,12 +87,24 @@ final class AcademyPromptPackController extends Controller
|
||||
->firstOrFail();
|
||||
|
||||
$payload = $this->access->packPayload($pack, $request->user(), true);
|
||||
$seo = app(SeoFactory::class)->collectionPage(
|
||||
$pack->title . ' — Skinbase Academy',
|
||||
Str::limit((string) ($pack->excerpt ?? $pack->description ?? ''), 160, '...'),
|
||||
route('academy.packs.show', ['slug' => $pack->slug]),
|
||||
$pack->cover_image,
|
||||
)->toArray();
|
||||
$canonical = route('academy.packs.show', ['slug' => $pack->slug]);
|
||||
$description = Str::limit((string) ($pack->excerpt ?? $pack->description ?? ''), 160, '...');
|
||||
$seo = SeoDataBuilder::fromArray(
|
||||
app(SeoFactory::class)->collectionPage(
|
||||
$pack->title . ' — Skinbase Academy',
|
||||
$description,
|
||||
$canonical,
|
||||
$pack->cover_image,
|
||||
)->toArray()
|
||||
)
|
||||
->breadcrumbs([
|
||||
['name' => 'Academy', 'url' => route('academy.index')],
|
||||
['name' => 'Prompt Packs', 'url' => route('academy.packs.index')],
|
||||
['name' => (string) $pack->title, 'url' => $canonical],
|
||||
])
|
||||
->addJsonLd($this->packStructuredData($payload, $canonical, $description))
|
||||
->build()
|
||||
->toArray();
|
||||
|
||||
$interaction = $this->interactions->getInteractionState($request->user(), AcademyAnalyticsContentType::PROMPT_PACK, (int) $pack->id);
|
||||
|
||||
@@ -112,4 +132,58 @@ final class AcademyPromptPackController extends Controller
|
||||
],
|
||||
])->rootView('academy');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $payload
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function packStructuredData(array $payload, string $canonical, string $description): array
|
||||
{
|
||||
$image = trim((string) ($payload['cover_image'] ?? ''));
|
||||
$imageUrl = $image !== '' && preg_match('/^https?:\/\//i', $image) === 1 ? $image : ($image !== '' ? url($image) : null);
|
||||
$keywords = array_values((array) ($payload['tags'] ?? []));
|
||||
$isFree = (string) ($payload['access_level'] ?? 'free') === 'free';
|
||||
$promptEntries = collect((array) ($payload['prompts'] ?? []))
|
||||
->map(function (array $prompt): ?array {
|
||||
$title = trim((string) ($prompt['title'] ?? ''));
|
||||
$slug = trim((string) ($prompt['slug'] ?? ''));
|
||||
|
||||
if ($title === '' || $slug === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'@type' => 'ListItem',
|
||||
'position' => null,
|
||||
'item' => [
|
||||
'@type' => 'CreativeWork',
|
||||
'name' => $title,
|
||||
'url' => route('academy.prompts.show', ['slug' => $slug]),
|
||||
],
|
||||
];
|
||||
})
|
||||
->filter()
|
||||
->values()
|
||||
->map(function (array $item, int $index): array {
|
||||
$item['position'] = $index + 1;
|
||||
|
||||
return $item;
|
||||
})
|
||||
->all();
|
||||
|
||||
return array_filter([
|
||||
'@context' => 'https://schema.org',
|
||||
'@type' => ['CreativeWork', 'LearningResource'],
|
||||
'name' => (string) ($payload['title'] ?? 'Skinbase Academy prompt pack'),
|
||||
'description' => $description,
|
||||
'url' => $canonical,
|
||||
'image' => $imageUrl,
|
||||
'keywords' => $keywords !== [] ? $keywords : null,
|
||||
'isAccessibleForFree' => $isFree,
|
||||
'hasPart' => $promptEntries !== [] ? [
|
||||
'@type' => 'ItemList',
|
||||
'itemListElement' => $promptEntries,
|
||||
] : null,
|
||||
], fn (mixed $value): bool => $value !== null && $value !== '' && $value !== []);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user