activeChannel(); $channel->load('prefixes'); $activePrefix = null; if ($request->filled('prefix')) { $activePrefix = $channel->prefixes->firstWhere('slug', $request->prefix); } $publications = Publication::with(['post.author', 'prefix']) ->forChannel($channel) ->when($activePrefix, fn ($q) => $q->forPrefix($activePrefix)) ->latest('updated_at') ->paginate(25) ->withQueryString(); return view('admin::posts.index', compact('publications', 'channel', 'activePrefix')); } public function create(): View { $channel = $this->activeChannel(); $channel->load('prefixes'); $publication = new Publication(['status' => 'draft']); return view('admin::posts.create', compact('channel', 'publication')); } public function store(Request $request): RedirectResponse { $channel = $this->activeChannel(); $request->validate([ 'title' => ['required', 'string', 'max:255'], 'prefix_id' => ['required', Rule::exists('channel_prefix', 'prefix_id')->where('channel_id', $channel->id)], 'status' => ['required', 'in:draft,published,scheduled'], ]); $post = Post::create(['user_id' => Auth::id()]); $publication = $post->publications()->create([ 'channel_id' => $channel->id, 'prefix_id' => $request->prefix_id, 'title' => $request->title, 'status' => $request->status, ]); return redirect()->route('admin.posts.edit', $publication) ->with('success', 'Post created. Add content and save.'); } public function edit(Publication $post): View { abort_if($post->channel_id !== $this->activeChannel()->id, 403); $post->load(['blocks', 'post.publications', 'taxonomyTerms', 'prefix', 'channel.prefixes', 'channel.taxonomyTerms']); $channel = $post->channel; $channelTerms = $channel->taxonomyTerms; $prefixes = $channel->prefixes; $allChannels = Channel::with('prefixes')->get(); return view('admin::posts.edit', compact('post', 'channel', 'channelTerms', 'prefixes', 'allChannels')); } public function update(Request $request, Publication $post): RedirectResponse { $channel = $this->activeChannel(); abort_if($post->channel_id !== $channel->id, 403); $request->validate([ 'title' => ['required', 'string', 'max:255'], 'prefix_id' => ['required', Rule::exists('channel_prefix', 'prefix_id')->where('channel_id', $channel->id)], 'slug' => ['nullable', 'string', 'max:255'], 'status' => ['required', 'in:draft,published,scheduled'], 'published_at' => ['nullable', 'date'], 'excerpt' => ['nullable', 'string'], 'meta_title' => ['nullable', 'string', 'max:255'], 'meta_description' => ['nullable', 'string'], 'og_image' => ['nullable', 'string', 'max:255'], 'canonical_url' => ['nullable', 'string', 'max:255'], 'taxonomy_terms' => ['nullable', 'array'], 'taxonomy_terms.*' => [Rule::exists('taxonomy_terms', 'id')->where('channel_id', $channel->id)], 'blocks' => ['nullable', 'array'], 'blocks.*.type' => ['required_with:blocks', 'string', 'in:rich_text,image,video,taxonomy_list'], 'blocks.*.content' => ['required_with:blocks', 'array'], ]); $post->update([ 'prefix_id' => $request->prefix_id, 'title' => $request->title, 'excerpt' => $request->excerpt, 'slug' => $request->slug ?: null, 'status' => $request->status, 'published_at' => $request->status === 'published' && !$request->published_at ? now() : $request->published_at, 'meta_title' => $request->meta_title, 'meta_description' => $request->meta_description, 'og_image' => $request->og_image, 'canonical_url' => $request->canonical_url, ]); $post->taxonomyTerms()->sync($request->input('taxonomy_terms', [])); $post->blocks()->delete(); foreach ($request->input('blocks', []) as $i => $block) { $post->blocks()->create([ 'type' => $block['type'], 'content' => $block['content'], 'order' => $i, ]); } return back()->with('success', 'Post saved.'); } public function duplicate(Request $request, Publication $post): RedirectResponse { abort_if($post->channel_id !== $this->activeChannel()->id, 403); $request->validate([ 'channel_id' => ['required', 'exists:channels,id'], 'prefix_id' => ['required', 'exists:prefixes,id'], ]); $post->load(['blocks', 'taxonomyTerms']); $newPost = Post::create(['user_id' => Auth::id()]); $newPublication = $newPost->publications()->create([ 'channel_id' => $request->channel_id, 'prefix_id' => $request->prefix_id, 'title' => $post->title, 'excerpt' => $post->excerpt, 'slug' => $post->slug, 'status' => 'draft', 'published_at' => null, 'meta_title' => $post->meta_title, 'meta_description' => $post->meta_description, 'og_image' => $post->og_image, 'canonical_url' => null, ]); foreach ($post->blocks as $block) { $newPublication->blocks()->create([ 'type' => $block->type, 'content' => $block->content, 'order' => $block->order, ]); } if ((int) $request->channel_id === $post->channel_id) { $newPublication->taxonomyTerms()->sync($post->taxonomyTerms->pluck('id')); } session(['admin.active_channel_id' => (int) $request->channel_id]); return redirect()->route('admin.posts.edit', $newPublication) ->with('success', 'Post duplicated as draft.'); } public function destroy(Publication $post): RedirectResponse { abort_if($post->channel_id !== $this->activeChannel()->id, 403); $parentPost = $post->post; $post->delete(); if ($parentPost->publications()->doesntExist()) { $parentPost->delete(); } return redirect()->route('admin.posts.index') ->with('success', 'Post deleted.'); } }