feat: add career application support for blog authors and expand blog status workflows

This commit is contained in:
Ümit Tunç
2026-08-07 23:21:17 +03:00
parent 9b91b3c847
commit 32b3f5187d
10 changed files with 75 additions and 23 deletions
@@ -6,6 +6,7 @@ use App\Filament\Admin\Resources\Components\TranslationTabs;
use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\DateTimePicker; use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\FileUpload; use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\RichEditor; use Filament\Forms\Components\RichEditor;
use Filament\Schemas\Components\Section; use Filament\Schemas\Components\Section;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
@@ -80,11 +81,17 @@ class BlogForm
->helperText(__('blog.featured_image_helper')) ->helperText(__('blog.featured_image_helper'))
->columnSpanFull(), ->columnSpanFull(),
Placeholder::make('intern_author_info')
->label('Stajyer Yazarı')
->content(fn ($record) => $record?->careerApplication?->name ?? '-')
->visible(fn ($record) => $record?->career_application_id !== null)
->columnSpanFull(),
Select::make('author_id') Select::make('author_id')
->label(__('blog.author_field')) ->label(__('blog.author_field'))
->relationship('author', 'name') ->relationship('author', 'name')
->default(auth()->id()) ->nullable()
->required() ->placeholder('Boş bırakılırsa stajyer yazarı veya Trunçgil')
->columnSpanFull(), ->columnSpanFull(),
Select::make('category_id') Select::make('category_id')
@@ -110,7 +117,9 @@ class BlogForm
->label(__('blog.status_field')) ->label(__('blog.status_field'))
->options([ ->options([
'draft' => __('blog.status_draft'), 'draft' => __('blog.status_draft'),
'pending' => __('blog.status_pending'),
'published' => __('blog.status_published'), 'published' => __('blog.status_published'),
'rejected' => __('blog.status_rejected'),
'archived' => __('blog.status_archived'), 'archived' => __('blog.status_archived'),
]) ])
->default('draft') ->default('draft')
@@ -76,7 +76,13 @@ class BlogsTable
TextColumn::make('author.name') TextColumn::make('author.name')
->label(__('blog.table_author')) ->label(__('blog.table_author'))
->searchable() ->formatStateUsing(fn ($state, $record) => $record->author_name)
->searchable(query: function ($query, string $search) {
$query->where(function ($q) use ($search) {
$q->whereHas('author', fn ($sub) => $sub->where('name', 'like', "%{$search}%"))
->orWhereHas('careerApplication', fn ($sub) => $sub->where('name', 'like', "%{$search}%"));
});
})
->sortable(), ->sortable(),
TextColumn::make('category.name') TextColumn::make('category.name')
+10 -7
View File
@@ -20,7 +20,7 @@ class BlogController extends Controller
$settings = class_exists(Setting::class) ? (Setting::query()->first()) : null; $settings = class_exists(Setting::class) ? (Setting::query()->first()) : null;
$query = class_exists(Blog::class) $query = class_exists(Blog::class)
? Blog::with(['category', 'author']) ? Blog::with(['category', 'author', 'careerApplication'])
->withCount('comments') ->withCount('comments')
->published() ->published()
: null; : null;
@@ -29,6 +29,9 @@ class BlogController extends Controller
if ($query && $request->has('author') && $request->author) { if ($query && $request->has('author') && $request->author) {
$query = $query->where('author_id', $request->author); $query = $query->where('author_id', $request->author);
} }
if ($query && $request->has('intern') && $request->intern) {
$query = $query->where('career_application_id', $request->intern);
}
// Category filtresi // Category filtresi
if ($query && $request->has('category') && $request->category) { if ($query && $request->has('category') && $request->category) {
@@ -130,14 +133,14 @@ class BlogController extends Controller
if (!$request->ajax()) { if (!$request->ajax()) {
if (class_exists(Blog::class)) { if (class_exists(Blog::class)) {
// Karusel: Öne çıkarılan ya da en güncel 5 yazı // Karusel: Öne çıkarılan ya da en güncel 5 yazı
$carouselPosts = Blog::with(['category', 'author']) $carouselPosts = Blog::with(['category', 'author', 'careerApplication'])
->published() ->published()
->featured() ->featured()
->latest('published_at') ->latest('published_at')
->take(5) ->take(5)
->get(); ->get();
if ($carouselPosts->isEmpty()) { if ($carouselPosts->isEmpty()) {
$carouselPosts = Blog::with(['category', 'author']) $carouselPosts = Blog::with(['category', 'author', 'careerApplication'])
->published() ->published()
->latest('published_at') ->latest('published_at')
->take(5) ->take(5)
@@ -145,7 +148,7 @@ class BlogController extends Controller
} }
// Popüler Yazılar: En çok okunan 3 yazı // Popüler Yazılar: En çok okunan 3 yazı
$popularPosts = Blog::with(['category', 'author']) $popularPosts = Blog::with(['category', 'author', 'careerApplication'])
->published() ->published()
->orderBy('view_count', 'desc') ->orderBy('view_count', 'desc')
->take(3) ->take(3)
@@ -224,14 +227,14 @@ class BlogController extends Controller
if (!class_exists(Blog::class)) { if (!class_exists(Blog::class)) {
abort(404); abort(404);
} }
$post = Blog::with(['category', 'author']) $post = Blog::with(['category', 'author', 'careerApplication'])
->withCount('comments') ->withCount('comments')
->published() ->published()
->where('slug', $slug) ->where('slug', $slug)
->firstOrFail(); ->firstOrFail();
// İlgili blog gönderilerini al (aynı kategoriden, mevcut gönderi hariç) // İlgili blog gönderilerini al (aynı kategoriden, mevcut gönderi hariç)
$relatedPosts = Blog::with(['category', 'author']) $relatedPosts = Blog::with(['category', 'author', 'careerApplication'])
->withCount('comments') ->withCount('comments')
->published() ->published()
->where('id', '!=', $post->id) ->where('id', '!=', $post->id)
@@ -244,7 +247,7 @@ class BlogController extends Controller
// Eğer aynı kategoriden yeterli gönderi yoksa, diğer kategorilerden ekle // Eğer aynı kategoriden yeterli gönderi yoksa, diğer kategorilerden ekle
if ($relatedPosts->count() < 4) { if ($relatedPosts->count() < 4) {
$additionalPosts = Blog::with(['category', 'author']) $additionalPosts = Blog::with(['category', 'author', 'careerApplication'])
->withCount('comments') ->withCount('comments')
->published() ->published()
->where('id', '!=', $post->id) ->where('id', '!=', $post->id)
+30
View File
@@ -82,6 +82,36 @@ class Blog extends Model
return '/blog/' . $this->slug; return '/blog/' . $this->slug;
} }
public function getAuthorNameAttribute()
{
if ($this->author) {
return $this->author->name;
}
if ($this->careerApplication) {
return $this->careerApplication->name;
}
return __('blog.default_author');
}
public function getAuthorRoleAttribute()
{
if ($this->author && $this->author->role) {
return $this->author->role;
}
if ($this->careerApplication) {
return 'Stajyer Yazılım Geliştirici';
}
return 'Trunçgil Teknoloji Editörü';
}
public function getAuthorAvatarUrlAttribute()
{
if ($this->author && $this->author->avatar) {
return asset('storage/' . $this->author->avatar);
}
return asset('assets/img/avatars/u5.webp');
}
public function getFeaturedImageUrlAttribute() public function getFeaturedImageUrlAttribute()
{ {
if ($this->featured_image) { if ($this->featured_image) {
+1 -1
View File
@@ -61,7 +61,7 @@ class BlogStructuredData extends StructuredData
'inLanguage' => app()->getLocale(), 'inLanguage' => app()->getLocale(),
'author' => [ 'author' => [
'@type' => 'Person', '@type' => 'Person',
'name' => $post->author->name ?? __('blog.default_author'), 'name' => $post->author_name,
], ],
'publisher' => self::publisherNode(), 'publisher' => self::publisherNode(),
'datePublished' => $publishedAt->toIso8601String(), 'datePublished' => $publishedAt->toIso8601String(),
+2
View File
@@ -61,7 +61,9 @@ return [
// Status options // Status options
'status_draft' => 'Draft', 'status_draft' => 'Draft',
'status_pending' => 'Pending Approval',
'status_published' => 'Published', 'status_published' => 'Published',
'status_rejected' => 'Revision Requested',
'status_archived' => 'Archived', 'status_archived' => 'Archived',
// Messages // Messages
+2
View File
@@ -61,7 +61,9 @@ return [
// Status options // Status options
'status_draft' => 'Taslak', 'status_draft' => 'Taslak',
'status_pending' => 'Onay Bekliyor',
'status_published' => 'Yayınlandı', 'status_published' => 'Yayınlandı',
'status_rejected' => 'Revize İstendi',
'status_archived' => 'Arşivlendi', 'status_archived' => 'Arşivlendi',
// Messages // Messages
+3 -3
View File
@@ -37,11 +37,11 @@
<i class="uil uil-calendar-alt pr-[0.2rem] align-[-.05rem] before:content-['\e9ba']"></i> <i class="uil uil-calendar-alt pr-[0.2rem] align-[-.05rem] before:content-['\e9ba']"></i>
<span>{{ $cDate }}</span> <span>{{ $cDate }}</span>
</li> </li>
@if($cPost->author) @if($cPost->author || $cPost->careerApplication)
<li class="post-author inline-block before:content-[''] before:inline-block before:w-[0.2rem] before:h-[0.2rem] before:opacity-50 before:m-[0_.6rem_0] before:rounded-[100%] before:align-[.15rem] before:bg-[#aab0bc]"> <li class="post-author inline-block before:content-[''] before:inline-block before:w-[0.2rem] before:h-[0.2rem] before:opacity-50 before:m-[0_.6rem_0] before:rounded-[100%] before:align-[.15rem] before:bg-[#aab0bc]">
<span class="!text-[#aab0bc]"> <span class="!text-[#aab0bc]">
<i class="uil uil-user pr-[0.2rem] align-[-.05rem] before:content-['\ed6f']"></i> <i class="uil uil-user pr-[0.2rem] align-[-.05rem] before:content-['\ed6f']"></i>
<span>{{ $cPost->author->name }}</span> <span>{{ $cPost->author_name }}</span>
</span> </span>
</li> </li>
@endif @endif
@@ -349,7 +349,7 @@
"datePublished" => $p->published_at ? $p->published_at->toIso8601String() : $p->created_at->toIso8601String(), "datePublished" => $p->published_at ? $p->published_at->toIso8601String() : $p->created_at->toIso8601String(),
"author" => [ "author" => [
"@type" => "Person", "@type" => "Person",
"name" => $p->author ? $p->author->name : 'Trunçgil' "name" => $p->author_name
] ]
]; ];
} }
+8 -8
View File
@@ -22,7 +22,7 @@
<li class="post-author inline-block before:content-[''] before:inline-block before:w-[0.2rem] before:h-[0.2rem] before:opacity-50 before:m-[0_.6rem_0_.4rem] before:rounded-[100%] before:align-[.15rem] before:bg-[#aab0bc]"> <li class="post-author inline-block before:content-[''] before:inline-block before:w-[0.2rem] before:h-[0.2rem] before:opacity-50 before:m-[0_.6rem_0_.4rem] before:rounded-[100%] before:align-[.15rem] before:bg-[#aab0bc]">
<span class="!text-[0.8rem] !text-[#aab0bc]"> <span class="!text-[0.8rem] !text-[#aab0bc]">
<i class="uil uil-user pr-[0.2rem] align-[-.05rem] before:content-['\ed6f']"></i> <i class="uil uil-user pr-[0.2rem] align-[-.05rem] before:content-['\ed6f']"></i>
<span>{{ $post->author ? $post->author->name : 'Trunçgil' }}</span> <span>{{ $post->author_name }}</span>
</span> </span>
</li> </li>
</ul> </ul>
@@ -84,15 +84,15 @@
<div class="author-info xl:!flex lg:!flex md:!flex items-center !mb-3"> <div class="author-info xl:!flex lg:!flex md:!flex items-center !mb-3">
<div class="flex items-center"> <div class="flex items-center">
<figure class="w-12 h-12 !relative !mr-4 rounded-[100%]"> <figure class="w-12 h-12 !relative !mr-4 rounded-[100%]">
<img class="rounded-[50%]" alt="image" src="{{ $post->author && $post->author->avatar ? asset('storage/' . $post->author->avatar) : asset('assets/img/avatars/u5.webp') }}" onerror="this.src='{{ asset('assets/img/avatars/u5.webp') }}'" loading="lazy"> <img class="rounded-[50%]" alt="image" src="{{ $post->author_avatar_url }}" onerror="this.src='{{ asset('assets/img/avatars/u5.webp') }}'" loading="lazy">
</figure> </figure>
<div> <div>
<h6><a href="#" class="!text-[#343f52] hover:!text-[#e31e24]">{{ $post->author ? $post->author->name : 'Trunçgil' }}</a></h6> <h6><a href="#" class="!text-[#343f52] hover:!text-[#e31e24]">{{ $post->author_name }}</a></h6>
<span class="!text-[0.75rem] !text-[#aab0bc] m-0 p-0 list-none">{{ $post->author && $post->author->role ? $post->author->role : 'Trunçgil Teknoloji Editörü' }}</span> <span class="!text-[0.75rem] !text-[#aab0bc] m-0 p-0 list-none">{{ $post->author_role }}</span>
</div> </div>
</div> </div>
<div class="!mt-3 xl:!mt-0 lg:!mt-0 md:!mt-0 !ml-auto"> <div class="!mt-3 xl:!mt-0 lg:!mt-0 md:!mt-0 !ml-auto">
<a href="{{ route('blog.index', ['author' => $post->author_id]) }}" class="btn btn-sm btn-soft-ash !rounded-[50rem] btn-icon btn-icon-start !mb-0 hover:translate-y-[-0.15rem] hover:shadow-[0_0.25rem_0.75rem_rgba(30,34,40,0.15)]"><i class="uil uil-file-alt !mr-[0.3rem] before:content-['\eaec'] text-[.8rem]"></i> Tüm Yazıları</a> <a href="{{ $post->author_id ? route('blog.index', ['author' => $post->author_id]) : ($post->career_application_id ? route('blog.index', ['intern' => $post->career_application_id]) : route('blog.index')) }}" class="btn btn-sm btn-soft-ash !rounded-[50rem] btn-icon btn-icon-start !mb-0 hover:translate-y-[-0.15rem] hover:shadow-[0_0.25rem_0.75rem_rgba(30,34,40,0.15)]"><i class="uil uil-file-alt !mr-[0.3rem] before:content-['\eaec'] text-[.8rem]"></i> Tüm Yazıları</a>
</div> </div>
</div> </div>
<p>Trunçgil Teknoloji editörleri tarafından kaleme alınmış bu makalede teknoloji, yazılım geliştirme ve dijital dönüşüm konularına dair güncel gelişmeleri incelediniz. Destek ve sorularınız için bizimle iletişime geçebilirsiniz.</p> <p>Trunçgil Teknoloji editörleri tarafından kaleme alınmış bu makalede teknoloji, yazılım geliştirme ve dijital dönüşüm konularına dair güncel gelişmeleri incelediniz. Destek ve sorularınız için bizimle iletişime geçebilirsiniz.</p>
@@ -181,9 +181,9 @@
$publishedDate = $post->published_at ? $post->published_at->toIso8601String() : $post->created_at->toIso8601String(); $publishedDate = $post->published_at ? $post->published_at->toIso8601String() : $post->created_at->toIso8601String();
$modifiedDate = $post->updated_at ? $post->updated_at->toIso8601String() : $publishedDate; $modifiedDate = $post->updated_at ? $post->updated_at->toIso8601String() : $publishedDate;
$authorName = $post->author ? $post->author->name : 'Trunçgil'; $authorName = $post->author_name;
$authorRole = $post->author && $post->author->role ? $post->author->role : 'Trunçgil Teknoloji Editörü'; $authorRole = $post->author_role;
$authorUrl = route('blog.index', ['author' => $post->author_id ?? 1]); $authorUrl = $post->author_id ? route('blog.index', ['author' => $post->author_id]) : ($post->career_application_id ? route('blog.index', ['intern' => $post->career_application_id]) : route('blog.index'));
$siteName = setting('site_name', 'Trunçgil Teknoloji'); $siteName = setting('site_name', 'Trunçgil Teknoloji');
$siteLogo = setting('site_logo') ? (str_starts_with(setting('site_logo'), 'http') ? setting('site_logo') : asset('storage/' . ltrim(setting('site_logo'), '/'))) : asset('assets/img/logo.png'); $siteLogo = setting('site_logo') ? (str_starts_with(setting('site_logo'), 'http') ? setting('site_logo') : asset('storage/' . ltrim(setting('site_logo'), '/'))) : asset('assets/img/logo.png');
@@ -1,6 +1,6 @@
@php @php
// Blog modelinden published içerikleri çek // Blog modelinden published içerikleri çek
$blogs = \App\Models\Blog::with(['category', 'author']) $blogs = \App\Models\Blog::with(['category', 'author', 'careerApplication'])
->withCount('comments') ->withCount('comments')
->published() ->published()
->latest('published_at') ->latest('published_at')