Initial commit: Pireon Admin — headless admin panel and public API
Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer collective, backed by the Pireon OAuth identity server. The public site is a separate, server-rendered application consuming /api/public/v1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
76
app/Support/SiteUrls.php
Normal file
76
app/Support/SiteUrls.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* Builds the public-site URLs and hreflang alternates for a translatable
|
||||
* record.
|
||||
*
|
||||
* This lives in the API rather than the frontend for one reason: only the API
|
||||
* knows that `/ca/projectes/el-meu-projecte` and `/proyectos/mi-proyecto` are
|
||||
* the same record. Without it the frontend cannot emit correct `hreflang`
|
||||
* tags, and search engines treat the three languages as duplicates.
|
||||
*/
|
||||
final class SiteUrls
|
||||
{
|
||||
/**
|
||||
* Every locale in which a record has a slug, mapped to its public path.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public static function alternates(Model $record, string $type, string $slugField = 'slug'): array
|
||||
{
|
||||
$alternates = [];
|
||||
|
||||
foreach (array_keys(config('locales.supported')) as $locale) {
|
||||
$slug = $record->getTranslation($slugField, $locale, useFallbackLocale: false);
|
||||
|
||||
// A locale without its own slug has no URL of its own — emitting
|
||||
// one would advertise a page that does not exist.
|
||||
if (blank($slug)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$alternates[$locale] = self::path($type, $locale, (string) $slug);
|
||||
}
|
||||
|
||||
return $alternates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute URLs for the same set, ready to drop into `<link hreflang>`.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public static function absoluteAlternates(Model $record, string $type, string $slugField = 'slug'): array
|
||||
{
|
||||
return array_map(
|
||||
fn (string $path) => rtrim(config('site.url'), '/').$path,
|
||||
self::alternates($record, $type, $slugField),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The path a record occupies on the public site, e.g. "/ca/projectes/foo".
|
||||
*/
|
||||
public static function path(string $type, string $locale, string $slug): string
|
||||
{
|
||||
$segments = [];
|
||||
|
||||
if ($locale !== config('locales.default') || config('site.prefix_default_locale')) {
|
||||
$segments[] = $locale;
|
||||
}
|
||||
|
||||
if ($prefix = config("site.paths.{$type}.{$locale}")) {
|
||||
$segments[] = $prefix;
|
||||
}
|
||||
|
||||
$segments[] = $slug;
|
||||
|
||||
return '/'.implode('/', array_filter($segments, fn ($s) => $s !== ''));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user