🛠️ Enhance SEO: Add meta tags for services and meetups landing pages, including dynamic title, description, and image handling

This commit is contained in:
HolgerHatGarKeineNode
2025-12-07 05:14:52 +01:00
parent 95de6e96c9
commit 0750852f51
4 changed files with 53 additions and 15 deletions

View File

@@ -144,6 +144,16 @@ class extends Component {
} }
}; ?> }; ?>
@section('meta')
@php
$SEOData = SeoDataAttribute::getData('meetups_landingpage');
$SEOData->title = $this->event->meetup->name;
$SEOData->description = $this->event->meetup->intro ? str($this->event->meetup->intro)->limit(50) : $SEOData->description;
$SEOData->image = $this->event->meetup->getFirstMediaUrl('logo');
@endphp
{!! seo($SEOData)->render() !!}
@endsection
<div class="container mx-auto px-4 py-8"> <div class="container mx-auto px-4 py-8">
<!-- Breadcrumb --> <!-- Breadcrumb -->
<div class="mb-6"> <div class="mb-6">

View File

@@ -4,8 +4,8 @@ use App\Attributes\SeoDataAttribute;
use App\Models\Meetup; use App\Models\Meetup;
use App\Models\MeetupEvent; use App\Models\MeetupEvent;
use App\Traits\SeoTrait; use App\Traits\SeoTrait;
use Livewire\Volt\Component;
use Flux\Flux; use Flux\Flux;
use Livewire\Volt\Component;
new new
#[SeoDataAttribute(key: 'meetups_landingpage')] #[SeoDataAttribute(key: 'meetups_landingpage')]
@@ -44,6 +44,16 @@ class extends Component {
} }
}; ?> }; ?>
@section('meta')
@php
$SEOData = SeoDataAttribute::getData('meetups_landingpage');
$SEOData->title = $this->meetup->name;
$SEOData->description = $this->meetup->intro ? str($this->meetup->intro)->limit(50) : $SEOData->description;
$SEOData->image = $this->meetup->getFirstMediaUrl('logo');
@endphp
{!! seo($SEOData)->render() !!}
@endsection
<div class="container mx-auto px-4 py-8"> <div class="container mx-auto px-4 py-8">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8"> <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<!-- Left Column: Meetup Details --> <!-- Left Column: Meetup Details -->

View File

@@ -42,6 +42,15 @@ class extends Component {
} }
}; ?> }; ?>
@section('meta')
@php
$SEOData = SeoDataAttribute::getData('meetups_landingpage');
$SEOData->title = $this->service->name;
$SEOData->description = $this->service->intro ? str($this->service->intro)->limit(50) : $SEOData->description;
@endphp
{!! seo($SEOData)->render() !!}
@endsection
<div class="container mx-auto px-4 py-8 max-w-5xl"> <div class="container mx-auto px-4 py-8 max-w-5xl">
<!-- Header --> <!-- Header -->
<div class="mb-8"> <div class="mb-8">
@@ -50,7 +59,8 @@ class extends Component {
@auth @auth
@if(auth()->id() === $service->created_by) @if(auth()->id() === $service->created_by)
<div class="flex gap-2"> <div class="flex gap-2">
<flux:button :href="route_with_country('services.edit', ['service' => $service])" variant="primary" icon="pencil"> <flux:button :href="route_with_country('services.edit', ['service' => $service])"
variant="primary" icon="pencil">
{{ __('Bearbeiten') }} {{ __('Bearbeiten') }}
</flux:button> </flux:button>
<flux:modal.trigger name="delete-service"> <flux:modal.trigger name="delete-service">
@@ -101,26 +111,30 @@ class extends Component {
<flux:heading size="lg" class="mb-4">{{ __('Zugriff') }}</flux:heading> <flux:heading size="lg" class="mb-4">{{ __('Zugriff') }}</flux:heading>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
@if($service->url_clearnet) @if($service->url_clearnet)
<flux:link :href="$service->url_clearnet" external class="text-blue-600 dark:text-blue-400 flex items-center gap-2"> <flux:link :href="$service->url_clearnet" external
<flux:icon.globe-alt variant="mini" /> class="text-blue-600 dark:text-blue-400 flex items-center gap-2">
<flux:icon.globe-alt variant="mini"/>
<span>Clearnet</span> <span>Clearnet</span>
</flux:link> </flux:link>
@endif @endif
@if($service->url_onion) @if($service->url_onion)
<flux:link :href="$service->url_onion" external class="text-purple-600 dark:text-purple-400 flex items-center gap-2"> <flux:link :href="$service->url_onion" external
<flux:icon.lock-closed variant="mini" /> class="text-purple-600 dark:text-purple-400 flex items-center gap-2">
<flux:icon.lock-closed variant="mini"/>
<span>Onion / Tor</span> <span>Onion / Tor</span>
</flux:link> </flux:link>
@endif @endif
@if($service->url_i2p) @if($service->url_i2p)
<flux:link :href="$service->url_i2p" external class="text-green-600 dark:text-green-400 flex items-center gap-2"> <flux:link :href="$service->url_i2p" external
<flux:icon.link variant="mini" /> class="text-green-600 dark:text-green-400 flex items-center gap-2">
<flux:icon.link variant="mini"/>
<span>I2P</span> <span>I2P</span>
</flux:link> </flux:link>
@endif @endif
@if($service->url_pkdns) @if($service->url_pkdns)
<flux:link :href="$service->url_pkdns" external class="text-orange-600 dark:text-orange-400 flex items-center gap-2"> <flux:link :href="$service->url_pkdns" external
<flux:icon.link variant="mini" /> class="text-orange-600 dark:text-orange-400 flex items-center gap-2">
<flux:icon.link variant="mini"/>
<span>pkdns</span> <span>pkdns</span>
</flux:link> </flux:link>
@endif @endif
@@ -136,7 +150,7 @@ class extends Component {
<div class="text-gray-500 dark:text-gray-400 mb-1">{{ __('Erstellt von') }}</div> <div class="text-gray-500 dark:text-gray-400 mb-1">{{ __('Erstellt von') }}</div>
@if($service->createdBy) @if($service->createdBy)
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<flux:avatar size="xs" src="{{ $service->createdBy->profile_photo_url }}" /> <flux:avatar size="xs" src="{{ $service->createdBy->profile_photo_url }}"/>
<span class="font-medium">{{ $service->createdBy->name }}</span> <span class="font-medium">{{ $service->createdBy->name }}</span>
</div> </div>
@else @else
@@ -148,7 +162,7 @@ class extends Component {
<div> <div>
<div class="text-gray-500 dark:text-gray-400 mb-1">{{ __('Erstellt am') }}</div> <div class="text-gray-500 dark:text-gray-400 mb-1">{{ __('Erstellt am') }}</div>
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
<flux:icon.plus variant="micro" class="text-green-600 dark:text-green-400" /> <flux:icon.plus variant="micro" class="text-green-600 dark:text-green-400"/>
<span>{{ $service->created_at->format('d.m.Y H:i') }}</span> <span>{{ $service->created_at->format('d.m.Y H:i') }}</span>
</div> </div>
</div> </div>
@@ -158,7 +172,7 @@ class extends Component {
<div> <div>
<div class="text-gray-500 dark:text-gray-400 mb-1">{{ __('Zuletzt aktualisiert') }}</div> <div class="text-gray-500 dark:text-gray-400 mb-1">{{ __('Zuletzt aktualisiert') }}</div>
<div class="flex items-center gap-1"> <div class="flex items-center gap-1">
<flux:icon.pencil variant="micro" class="text-blue-600 dark:text-blue-400" /> <flux:icon.pencil variant="micro" class="text-blue-600 dark:text-blue-400"/>
<span>{{ $service->updated_at->format('d.m.Y H:i') }}</span> <span>{{ $service->updated_at->format('d.m.Y H:i') }}</span>
</div> </div>
</div> </div>
@@ -183,7 +197,7 @@ class extends Component {
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<flux:spacer /> <flux:spacer/>
<flux:modal.close> <flux:modal.close>
<flux:button variant="ghost">{{ __('Abbrechen') }}</flux:button> <flux:button variant="ghost">{{ __('Abbrechen') }}</flux:button>
</flux:modal.close> </flux:modal.close>

View File

@@ -1,7 +1,11 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
{!! seo($SEOData) !!} @hasSection('meta')
@yield('meta')
@else
{!! seo($SEOData) !!}
@endif
<link rel="apple-touch-icon" href="/img/apple_touch_icon.png"/> <link rel="apple-touch-icon" href="/img/apple_touch_icon.png"/>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">