SEO additions

This commit is contained in:
Mark Gregory
2026-10-01 11:15:55 +01:00
parent a94f294184
commit a8eff45f49
18 changed files with 493 additions and 24 deletions
+11 -1
View File
@@ -6,7 +6,17 @@
<label>Slug<input name="slug" value="{{ old('slug',$page->slug) }}" placeholder="generated-from-title" maxlength="180"></label>
<label>Excerpt<textarea name="excerpt" rows="3" maxlength="1000">{{ old('excerpt',$page->excerpt) }}</textarea></label>
<label>Body<textarea name="body" rows="18" required>{{ old('body',$page->body) }}</textarea><small>Plain text is rendered safely with paragraphs and line breaks.</small></label>
<div class="form-grid two"><label>SEO title<input name="meta_title" value="{{ old('meta_title',$page->meta_title) }}" maxlength="160"></label><label>SEO description<textarea name="meta_description" rows="3" maxlength="320">{{ old('meta_description',$page->meta_description) }}</textarea></label></div>
<section class="seo-section" style="padding:24px 0 4px;border-top:1px solid var(--line);margin-top:24px">
<div class="seo-section-head"><div><span class="eyebrow">Search appearance</span><h2>Page SEO</h2><p>Override global defaults only where this page needs specific search or social metadata.</p></div><a class="btn btn-secondary" href="{{ route('admin.seo.edit') }}">Global SEO settings</a></div>
<div class="form-grid two"><label>SEO title<input name="meta_title" value="{{ old('meta_title',$page->meta_title) }}" maxlength="160" placeholder="Defaults to the page title"></label><label>Canonical URL<input type="url" name="canonical_url" value="{{ old('canonical_url',$page->canonical_url) }}" maxlength="2048" placeholder="Leave blank for this page URL"></label></div>
<label>SEO description<textarea name="meta_description" rows="3" maxlength="320" placeholder="Defaults to the excerpt">{{ old('meta_description',$page->meta_description) }}</textarea></label>
<label>Keywords<input name="meta_keywords" value="{{ old('meta_keywords',$page->meta_keywords) }}" maxlength="500" placeholder="Optional comma-separated search topics"></label>
<div class="form-grid two"><label>Open Graph title<input name="og_title" value="{{ old('og_title',$page->og_title) }}" maxlength="160" placeholder="Defaults to SEO title"></label><label>Open Graph image URL<input type="url" name="og_image" value="{{ old('og_image',$page->og_image) }}" maxlength="2048" placeholder="Defaults to global social image"></label></div>
<label>Open Graph description<textarea name="og_description" rows="3" maxlength="320" placeholder="Defaults to SEO description">{{ old('og_description',$page->og_description) }}</textarea></label>
<div class="form-grid two"><label>Sitemap priority<input type="number" name="sitemap_priority" value="{{ old('sitemap_priority',$page->sitemap_priority ?? '0.5') }}" min="0" max="1" step="0.1" required></label><label>Change frequency<select name="sitemap_change_frequency" required>@foreach(['always','hourly','daily','weekly','monthly','yearly','never'] as $frequency)<option value="{{ $frequency }}" @selected(old('sitemap_change_frequency',$page->sitemap_change_frequency ?? 'monthly') === $frequency)>{{ ucfirst($frequency) }}</option>@endforeach</select></label></div>
<div class="form-grid two"><label class="consent-check"><input type="checkbox" name="robots_index" value="1" @checked(old('robots_index',$page->exists ? $page->robots_index : true))><span>Allow search engines to index this page</span></label><label class="consent-check"><input type="checkbox" name="robots_follow" value="1" @checked(old('robots_follow',$page->exists ? $page->robots_follow : true))><span>Allow crawlers to follow links</span></label></div>
<label class="consent-check"><input type="checkbox" name="include_in_sitemap" value="1" @checked(old('include_in_sitemap',$page->exists ? $page->include_in_sitemap : true))><span>Include this page in sitemap.xml</span></label>
</section>
<label class="consent-check"><input type="checkbox" name="is_published" value="1" @checked(old('is_published',$page->is_published))><span>Published</span></label>
<div class="support-actions"><button type="submit">Save page</button>@if($page->exists && $page->is_published)<a class="btn btn-secondary" target="_blank" href="{{ route('cms.show',$page->slug) }}">View page</a>@endif</div>
</form></div>
+1 -1
View File
@@ -2,5 +2,5 @@
@section('content')
<section class="portal-header"><div><span class="eyebrow">Admin</span><h1>Licensing administration</h1><p class="lead compact">Manage licences, activations and customer support.</p></div></section>
<div class="grid"><div class="card"><strong>{{ $licenseCount }}</strong><p>Licences</p></div><div class="card"><strong>{{ $activeCount }}</strong><p>Not revoked</p></div><div class="card"><strong>{{ $activationCount }}</strong><p>Active installations</p></div><div class="card"><strong>{{ $userCount }}</strong><p>Portal users</p></div></div>
<div style="display:flex;gap:10px;flex-wrap:wrap;margin-top:18px"><a class="btn btn-primary" href="{{ route('admin.releases.index') }}">Manage releases</a><a class="btn" href="{{ route('admin.licenses') }}">Manage licences</a><a class="btn btn-secondary" href="{{ route('admin.cms.index') }}">Manage content</a><a class="btn btn-secondary" href="{{ route('admin.support.index') }}">Support inbox</a></div>
<div style="display:flex;gap:10px;flex-wrap:wrap;margin-top:18px"><a class="btn btn-primary" href="{{ route('admin.releases.index') }}">Manage releases</a><a class="btn" href="{{ route('admin.licenses') }}">Manage licences</a><a class="btn btn-secondary" href="{{ route('admin.cms.index') }}">Manage content</a><a class="btn btn-secondary" href="{{ route('admin.seo.edit') }}">SEO & search</a><a class="btn btn-secondary" href="{{ route('admin.support.index') }}">Support inbox</a></div>
@endsection
+39
View File
@@ -0,0 +1,39 @@
@extends('layouts.app')
@section('content')
<section class="portal-header admin-release-head">
<div><span class="eyebrow">Search & discovery</span><h1>SEO settings</h1><p class="lead compact">Control how SonarDesk appears in search engines and when pages are shared.</p></div>
<div class="support-actions"><a class="btn btn-secondary" target="_blank" href="{{ route('sitemap') }}">View sitemap</a><a class="btn btn-secondary" target="_blank" href="{{ route('robots') }}">View robots.txt</a></div>
</section>
<form method="post" action="{{ route('admin.seo.update') }}" class="seo-admin-form">@csrf @method('PUT')
<section class="panel seo-section">
<div class="seo-section-head"><div><span class="eyebrow">Search appearance</span><h2>Site defaults</h2><p>Fallback metadata used whenever a page does not provide its own SEO values.</p></div><span class="seo-badge">Global</span></div>
<div class="form-grid two">
<label>Site name<input name="seo_site_name" value="{{ old('seo_site_name',$settings['seo_site_name'] ?: 'SonarDesk') }}" required maxlength="80"></label>
<label>Title suffix<input name="seo_title_suffix" value="{{ old('seo_title_suffix',$settings['seo_title_suffix'] ?: 'SonarDesk') }}" maxlength="80"><small>Appended to page titles where appropriate.</small></label>
</div>
<label>Default SEO title<input name="seo_default_title" value="{{ old('seo_default_title',$settings['seo_default_title'] ?: 'SonarDesk — Native SonarQube Monitoring for macOS') }}" required maxlength="160"></label>
<label>Default meta description<textarea name="seo_default_description" rows="3" maxlength="320" required>{{ old('seo_default_description',$settings['seo_default_description'] ?: 'Native SonarQube monitoring for macOS. Track projects, quality gates, bugs, vulnerabilities and code smells from one professional desktop app.') }}</textarea></label>
<label>Default keywords<input name="seo_default_keywords" value="{{ old('seo_default_keywords',$settings['seo_default_keywords']) }}" maxlength="500" placeholder="SonarQube, macOS, code quality, developer tools"></label>
<label>Canonical base URL<input type="url" name="seo_canonical_base_url" value="{{ old('seo_canonical_base_url',$settings['seo_canonical_base_url']) }}" maxlength="2048" placeholder="https://sonardesk.app"><small>Leave blank to use the application URL. Use the public production origin only.</small></label>
</section>
<section class="panel seo-section">
<div class="seo-section-head"><div><span class="eyebrow">Social sharing</span><h2>Open Graph & social</h2><p>Professional defaults for link previews across social networks and messaging applications.</p></div></div>
<label>Default social image URL<input type="url" name="seo_default_og_image" value="{{ old('seo_default_og_image',$settings['seo_default_og_image']) }}" maxlength="2048" placeholder="https://…/og-sonardesk.png"><small>Recommended: 1200 × 630 px.</small></label>
<div class="form-grid two"><label>Organization name<input name="seo_organization_name" value="{{ old('seo_organization_name',$settings['seo_organization_name'] ?: 'SonarDesk') }}" maxlength="120"></label><label>Organization logo URL<input type="url" name="seo_organization_logo" value="{{ old('seo_organization_logo',$settings['seo_organization_logo']) }}" maxlength="2048"></label></div>
<label>X / Twitter account<input name="seo_twitter_site" value="{{ old('seo_twitter_site',$settings['seo_twitter_site']) }}" maxlength="40" placeholder="@SonarDesk"></label>
</section>
<section class="panel seo-section">
<div class="seo-section-head"><div><span class="eyebrow">Google Search Console</span><h2>Domain verification</h2><p>Use a Domain property in Google Search Console. Google will provide a TXT value that you add at your DNS provider.</p></div><span class="seo-badge success">DNS TXT</span></div>
<div class="seo-dns-callout"><strong>Recommended verification method</strong><span>Add Google’s <code>google-site-verification=…</code> TXT record to the root domain. DNS verification covers all protocols and subdomains.</span></div>
<label>Optional Google verification token<input name="seo_google_site_verification" value="{{ old('seo_google_site_verification',$settings['seo_google_site_verification']) }}" maxlength="255" placeholder="Only needed if you also choose HTML-tag verification"><small>DNS TXT verification does not require this field. It is available as a secondary verification method.</small></label>
</section>
<section class="panel seo-section">
<div class="seo-section-head"><div><span class="eyebrow">Crawler control</span><h2>Indexing</h2><p>Production crawler controls. Non-production environments remain blocked automatically.</p></div></div>
<label class="consent-check"><input type="checkbox" name="seo_robots_enabled" value="1" @checked(old('seo_robots_enabled',$robotsEnabled))><span><strong>Allow production search-engine indexing</strong><small>When disabled, robots.txt blocks crawling and pages emit noindex.</small></span></label>
</section>
<div class="seo-savebar"><div><strong>Search configuration</strong><span>Changes apply to public metadata immediately.</span></div><button type="submit" class="btn btn-primary">Save SEO settings</button></div>
</form>
@endsection