@extends('admin.layouts.app') @section('title', 'SEO System') @section('page_title', 'SEO System') @section('content') @php $tab = $tab ?? 'overview'; $tabs = [ 'overview' => ['label' => 'Overview', 'hint' => 'Robots & sitemap'], 'settings' => ['label' => 'Settings', 'hint' => 'Defaults & llms'], 'audits' => ['label' => 'Audits', 'hint' => 'Low scores'], '404' => ['label' => '404 Monitor', 'hint' => 'Broken paths'], 'keywords' => ['label' => 'Keywords', 'hint' => 'Rank tracking'], 'bulk' => ['label' => 'Bulk Editor', 'hint' => 'CSV & mass edit'], 'workouts' => ['label' => 'Workouts', 'hint' => 'Content health'], 'reports' => ['label' => 'Reports', 'hint' => 'Wins & losses'], ]; $avgLow = $lowScores->count() ? (int) round($lowScores->avg('score')) : null; $sitemapTotal = (int) ($sitemapStats['total'] ?? 0); $lastGenerated = $sitemapStats['last_generated'] ?? null; @endphp

Site · Search intelligence

SEO command center

Robots, sitemaps, audits, keywords, and content workouts — one premium workspace for search performance.

Open sitemap.xml Open robots.txt @can('update', \Apex\Modules\SEO\Models\SeoAudit::class)
@csrf
@endcan
Sitemap URLs {{ number_format($sitemapTotal) }} Low scores {{ $lowScores->count() }} 404 paths {{ $notFound->count() }} Keywords {{ $trackedKeywords->count() }} @if(! is_null($avgLow)) Avg low score {{ $avgLow }} @endif
@foreach ($tabs as $key => $meta) {{ $meta['label'] }} {{ $meta['hint'] }} @endforeach
@if($tab === 'overview')

robots.txt

Crawl rules for search engines. AI blockers append from Settings when enabled.

View live
@csrf @can('update', \Apex\Modules\SEO\Models\SeoAudit::class) @endcan

Sitemaps & discovery

XML index health and AI discovery files.

Total URLs
{{ number_format($sitemapTotal) }}
Last generated
{{ $lastGenerated ? \Carbon\Carbon::parse($lastGenerated)->diffForHumans() : 'Never' }}
@can('update', \Apex\Modules\SEO\Models\SeoAudit::class) @endcan
@endif @if($tab === 'settings')

Global SEO settings

Title templates, AI bot policy, llms.txt, and white-label report branding.

@csrf

Variables: %%title%% %%sep%% %%sitename%% %%focuskw%% %%excerpt%% %%currentyear%%

@endif @if($tab === 'audits')

Low SEO scores

Pages scoring under 80 — prioritize fixes here first.

@forelse ($lowScores as $audit) @php $scoreClass = $audit->score >= 60 ? 'is-mid' : 'is-low'; @endphp @empty @endforelse
URL Score Checked

{{ $audit->url }}

{{ $audit->score }}/100 {{ $audit->checked_at?->diffForHumans() ?? '—' }}
No audit data yet. Queue bulk audits from Overview.
@endif @if($tab === '404')

404 monitor

Broken paths by hit volume — create redirects or ignore noise.

Manage redirects
@forelse($notFound as $log) @empty @endforelse
Path Hits Last seen Referer Actions

{{ $log->path }}

{{ $log->hits }} {{ $log->last_hit_at?->diffForHumans() ?? '—' }}

{{ $log->referer ?: '—' }}

Redirect
@csrf
No 404s logged. Looking healthy.
@endif @if($tab === 'keywords')

Track keyword

Add a focus term and optional current rank.

@csrf

Tracked keywords

Position, movement, and best rank.

@forelse($trackedKeywords as $kw) @php $delta = $kw->positionDelta(); @endphp @empty @endforelse
Keyword Pos Δ Best Actions

{{ $kw->keyword }}

@if($kw->target_url)

{{ $kw->target_url }}

@endif
{{ $kw->current_position ?? '—' }} @if($delta === null) — @elseif($delta > 0) +{{ $delta }} @elseif($delta < 0) {{ $delta }} @else 0 @endif {{ $kw->best_position ?? '—' }}
@csrf
@csrf @method('DELETE')
No keywords tracked yet.
@endif @if($tab === 'bulk')

Bulk SEO editor

Edit titles, descriptions, focus keywords, and robots in one pass.

Export CSV
@csrf
@csrf
@forelse($bulkRows as $i => $row) @empty @endforelse
Type / ID Title Description Focus Robots

{{ class_basename($row->metaable_type) }}

#{{ $row->metaable_id }}

No SEO meta rows available for bulk edit.
@if($bulkRows->count()) @endif
@endif @if($tab === 'workouts')

Orphaned content

Pages with weak internal linking signals.

    @forelse($orphans as $item)
  • {{ $item['title'] }} {{ $item['type'] }}
  • @empty
  • No orphans detected.
  • @endforelse

Cornerstone

Priority pages marked as cornerstone.

    @forelse($cornerstone as $item)
  • {{ $item['title'] }} {{ $item['type'] }} · {{ $item['updated_at'] }}
  • @empty
  • Mark content as cornerstone in the SEO editor.
  • @endforelse

Stale content

Not updated in 6+ months.

    @forelse($stale as $item)
  • {{ $item['title'] }} {{ $item['type'] }} · {{ $item['updated_at'] }}
  • @empty
  • Nothing stale.
  • @endforelse
@endif @if($tab === 'reports')

Winning keywords

Positive rank movement since last update.

    @forelse($winning as $kw)
  • {{ $kw->keyword }} +{{ $kw->positionDelta() }}
  • @empty
  • No movement data yet. Update ranks or connect GSC.
  • @endforelse

Losing keywords

Negative movement that needs attention.

    @forelse($losing as $kw)
  • {{ $kw->keyword }} {{ $kw->positionDelta() }}
  • @empty
  • No losses recorded.
  • @endforelse

White-label report branding is configured under Settings.

@endif
@endsection