Track and display subdomains under their root domain
Adds sites.root_domain (indexed string, backfilled for existing rows)
computed via a naive "last two labels" heuristic (App\Support\RootDomain)
— good enough for example.com/somesite.es, but wrong for two-part
public suffixes like .co.uk. Doing that correctly needs the Mozilla
Public Suffix List; flagged as a known simplification rather than
built now.
Deliberately not a hard FK: like Backlink.target_domain, a subdomain
can get indexed before its root domain does (or vice versa), so
Site::subdomains()/rootSite() match on the domain string rather than
requiring the relationship to exist at write time.
Site detail page: a root domain shows a paginated "Subdomains"
section (same guest-preview cap as Pages/Backlinks); a subdomain
shows "Subdomain of {root}" linking back, when the root is itself
indexed.
Verified against real data: 21k.ro correctly lists its two known
subdomains (buzau.21k.ro, timisoara.21k.ro), each of which correctly
links back to 21k.ro. Added SubdomainsTest (root lists subdomains,
subdomain links to root, empty state) — full suite (31 tests) passes.
This commit is contained in:
@@ -4,6 +4,13 @@
|
||||
|
||||
<h1 class="mt-2 text-2xl font-semibold">{{ $site->domain }}</h1>
|
||||
|
||||
@if ($rootSite)
|
||||
<p class="mt-1 text-sm text-neutral-500">
|
||||
Subdomain of
|
||||
<a href="{{ route('sites.show', $rootSite) }}" class="text-blue-600 hover:underline dark:text-blue-400">{{ $rootSite->domain }}</a>
|
||||
</p>
|
||||
@endif
|
||||
|
||||
@if ($site->title)
|
||||
<p class="mt-1 text-neutral-700 dark:text-neutral-300">{{ $site->title }}</p>
|
||||
@endif
|
||||
@@ -137,5 +144,44 @@
|
||||
<x-guest-preview-notice :paginator="$backlinks" />
|
||||
@endauth
|
||||
</div>
|
||||
|
||||
<h2 class="mt-10 text-lg font-medium">Subdomains ({{ $subdomains->total() }})</h2>
|
||||
|
||||
<div class="mt-4 overflow-hidden rounded-lg border border-neutral-200 dark:border-neutral-800">
|
||||
<table class="min-w-full divide-y divide-neutral-200 dark:divide-neutral-800">
|
||||
<thead class="bg-neutral-50 dark:bg-neutral-900">
|
||||
<tr>
|
||||
<th class="px-4 py-2 text-left text-xs font-medium uppercase tracking-wide text-neutral-500">Subdomain</th>
|
||||
<th class="px-4 py-2 text-left text-xs font-medium uppercase tracking-wide text-neutral-500">Title</th>
|
||||
<th class="px-4 py-2 text-right text-xs font-medium uppercase tracking-wide text-neutral-500">Pages</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-neutral-200 dark:divide-neutral-800">
|
||||
@forelse ($subdomains as $subdomain)
|
||||
<tr>
|
||||
<td class="px-4 py-2 text-sm">
|
||||
<a href="{{ route('sites.show', $subdomain) }}" class="font-medium text-blue-600 hover:underline dark:text-blue-400">
|
||||
{{ $subdomain->domain }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="px-4 py-2 text-sm text-neutral-600 dark:text-neutral-400">{{ $subdomain->title ?? '—' }}</td>
|
||||
<td class="px-4 py-2 text-right text-sm text-neutral-600 dark:text-neutral-400">{{ $subdomain->pages_count }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="3" class="px-4 py-6 text-center text-sm text-neutral-500">No subdomains found.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
@auth
|
||||
{{ $subdomains->links() }}
|
||||
@else
|
||||
<x-guest-preview-notice :paginator="$subdomains" />
|
||||
@endauth
|
||||
</div>
|
||||
</div>
|
||||
</x-layouts.app>
|
||||
|
||||
Reference in New Issue
Block a user