withCount('contentPlacements') ->when($request->string('search')->isNotEmpty(), function ($query) use ($request): void { $search = $request->string('search')->toString(); $query->where(fn ($page) => $page ->where('title', 'like', "%{$search}%") ->orWhere('slug', 'like', "%{$search}%") ->orWhere('summary', 'like', "%{$search}%")); }) ->when($request->string('status')->isNotEmpty(), fn ($query) => $query->where('status', $request->string('status')->toString())) ->orderByDesc('is_home') ->orderBy('title') ->paginate(24) ->withQueryString(); return view('pages::admin.index', compact('records')); } public function create(): View { return view('pages::admin.form', ['record' => new Page(['status' => 'draft', 'template' => 'default'])]); } public function store(Request $request): RedirectResponse { $data = $this->validated($request); $data['slug'] = $this->uniqueSlug($data['slug'] ?: $data['title']); $data['is_home'] = $request->boolean('is_home'); $data['published_at'] = $data['status'] === 'published' ? ($data['published_at'] ?? now()) : null; $page = Page::query()->create($data); $this->enforceSingleHomepage($page); return redirect()->route('administration.pages.edit', $page)->with('status', 'Page created. Add content sections when you are ready.'); } public function edit(Page $page): View { $page->loadCount('contentPlacements'); return view('pages::admin.form', ['record' => $page]); } public function update(Request $request, Page $page): RedirectResponse { $oldSlug = $page->slug; $data = $this->validated($request, $page); $data['slug'] = $this->uniqueSlug($data['slug'] ?: $data['title'], $page); $data['is_home'] = $request->boolean('is_home'); $data['published_at'] = $data['status'] === 'published' ? ($data['published_at'] ?? $page->published_at ?? now()) : null; $page->update($data); $this->enforceSingleHomepage($page); if ($oldSlug !== $page->slug) { PageContent::query()->where('page_id', $page->id)->orWhere('page_key', $oldSlug)->update(['page_key' => $page->slug, 'page_id' => $page->id]); } return back()->with('status', 'Page saved.'); } public function duplicate(Request $request, Page $page): RedirectResponse { $copy = $page->replicate(['slug', 'status', 'published_at', 'preview_token', 'locked_by', 'locked_at', 'is_home']); $copy->title = $page->title.' copy'; $copy->slug = $this->uniqueSlug($copy->title); $copy->status = 'draft'; $copy->published_at = null; $copy->is_home = false; $copy->save(); foreach ($page->contentPlacements()->orderBy('region')->orderBy('sort_order')->get() as $placement) { $copy->contentPlacements()->create([ 'page_key' => $copy->slug, 'content_document_id' => $placement->content_document_id, 'region' => $placement->region, 'sort_order' => $placement->sort_order, 'is_enabled' => $placement->is_enabled, 'visibility_rules' => $placement->visibility_rules, 'presentation' => $placement->presentation, 'starts_at' => $placement->starts_at, 'ends_at' => $placement->ends_at, ]); } return redirect()->route('administration.pages.edit', $copy)->with('status', 'Draft copy created with the same content structure.'); } public function destroy(Page $page): RedirectResponse { if ($page->is_home) { return back()->withErrors(['page' => 'Choose another homepage before deleting the current homepage.']); } $page->delete(); return redirect()->route('administration.pages.index')->with('status', 'Page moved to the bin.'); } private function validated(Request $request, ?Page $page = null): array { return $request->validate([ 'title' => ['required', 'string', 'max:255'], 'slug' => ['nullable', 'string', 'max:255', Rule::unique('pages', 'slug')->ignore($page?->id)->whereNull('deleted_at')], 'summary' => ['nullable', 'string', 'max:1000'], 'content' => ['nullable', 'string'], 'status' => ['required', Rule::in(['draft', 'published'])], 'template' => ['required', Rule::in(['default', 'landing', 'full-width'])], 'published_at' => ['nullable', 'date'], 'expires_at' => ['nullable', 'date', 'after:published_at'], 'is_home' => ['sometimes', 'boolean'], ]); } private function uniqueSlug(string $value, ?Page $except = null): string { $base = Str::slug($value) ?: 'page'; $slug = $base; $suffix = 2; while (Page::withTrashed()->where('slug', $slug)->when($except, fn ($query) => $query->whereKeyNot($except->getKey()))->exists()) { $slug = $base.'-'.$suffix++; } return $slug; } private function enforceSingleHomepage(Page $page): void { if ($page->is_home) { Page::query()->whereKeyNot($page->id)->where('is_home', true)->update(['is_home' => false]); } } }