Yes, you can add tags to blog posts by creating a many-to-many relationship between posts and tags. This requires three tables:
posts
: Table to store blog posts.tags
: Table to store tags.post_tag
: Pivot table to associate posts with tags.
Run the following command to create a migration for the tags
table:
php artisan make:migration create_tags_table
Then, edit the migration file to include the necessary fields:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTagsTable extends Migration
{
public function up(): void
{
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('tags');
}
}
Run the following command to create a migration for the pivot table:
php artisan make:migration create_post_tag_table
Edit the generated migration file:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePostTagTable extends Migration
{
public function up(): void
{
Schema::create('post_tag', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained()->onDelete('cascade');
$table->foreignId('tag_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('post_tag');
}
}
public function tags()
{
return $this->belongsToMany(Tag::class, 'post_tag');
}
public function posts()
{
return $this->belongsToMany(Post::class, 'post_tag');
}
$post = Post::find(1);
$tag = Tag::where('name', 'Laravel')->first();
// Attach a tag
$post->tags()->attach($tag->id);
// Attach multiple tags
$post->tags()->attach([1, 2, 3]);
$post->tags()->detach($tag->id); // Detach a single tag
$post->tags()->detach(); // Detach all tags
$post->tags()->sync([1, 2, 3]); // Replace existing tags with these
Add a multi-select field for tags:
<div class="mb-3">
<label for="tags" class="form-label">Tags</label>
<select class="form-control" id="tags" name="tags[]" multiple>
@foreach($tags as $tag)
<option value="{{ $tag->id }}"
{{ isset($post) && $post->tags->contains($tag->id) ? 'selected' : '' }}>
{{ $tag->name }}
</option>
@endforeach
</select>
</div>
Handle tags in store
and update
methods:
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required',
'tags' => 'array', // Tags validation
'tags.*' => 'exists:tags,id',
]);
$post = Post::create($validated);
$post->tags()->sync($request->tags);
return redirect()->route('posts.index');
}
public function update(Request $request, Post $post)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required',
'tags' => 'array',
'tags.*' => 'exists:tags,id',
]);
$post->update($validated);
$post->tags()->sync($request->tags);
return redirect()->route('posts.index');
}
Let me know if you'd like to extend this further!