In this tutorial, we will see how to add tags to posts using many-to-many relationships.
Create Post Modal Migration Controller and Route
Run the following command to create the Post model, migration, and controller.
php artisan make:model Post -mcr
create_posts_table.php
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('slug');
$table->longText('description');
$table->timestamps();
});
}
Create Tags Modal and Migration
php artisan make:model Tag -m
create_tags_table.php
public function up()
{
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
Create Post Tag Pivot Table
Run below command to create post tag pivot table.
php artisan make:migration CreatePostTagTable
post_tag_table.php
public function up()
{
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();
});
}
Now create routes.
Route::resource('posts', PostController::class);
Create Tags Seeder
php artisan make:seeder TagSeeder
seeders/TagSeeder.php
<?php
namespace Database\Seeders;
use App\Models\Tag;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class TagSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$data = [
[
'name' => 'Laravel',
'created_at' => now(),
'updated_at' => now()
],
[
'name' => 'Node JS',
'created_at' => now(),
'updated_at' => now()
],
[
'name' => 'Python',
'created_at' => now(),
'updated_at' => now()
],
[
'name' => 'Java',
'created_at' => now(),
'updated_at' => now()
],
[
'name' => 'React',
'created_at' => now(),
'updated_at' => now()
],
];
Tag::insert($data);
}
}
seeders/DatabaseSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
$this->call(TagSeeder::class);
$this->command->info('Tag Seeder created.');
}
}
Add Tag Many to Many Relationships in Modal
Models/Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = [
'title',
'slug',
'description',
];
public function tags()
{
return $this->belongsToMany(Tag::class)->as('tags');
}
}
Models/Tag.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
use HasFactory;
protected $fillable = ['name'];
public function posts()
{
return $this->belongsToMany(Post::class);
}
}
Attach tags in PostController.php
using many-to-many relationships.
app/Http/Controllers/PostController.php
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use App\Models\Tag;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$posts = Post::with(['tags'])->latest()->paginate(10);
return view('posts.index', compact('posts'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
$tags = Tag::all();
return view('posts.create', compact('tags'));
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$request->validate([
'title' => 'required|string|max:255',
'slug' => 'required|string|max:255',
'description' => 'required'
]);
$post = Post::create([
'title' => $request->title,
'slug' => \Str::slug($request->slug),
'description' => $request->description,
]);
if ($request->has('tags')) {
$post->tags()->attach($request->tags);
}
return redirect()->route('posts.index')->with('status', 'Post Created Successfully');
}
}
Add Tags in Blade File
views/posts/create.blade.php
<form method="POST" action="{{ route('posts.store') }}">
@csrf
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Title</span>
<input type="text" name="title"
class="block w-full @error('title') border-red-500 @enderror mt-1 rounded-md" placeholder=""
value="{{old('title')}}" />
</label>
@error('title')
<div class="text-sm text-red-600">{{ $message }}</div>
@enderror
</div>
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Slug</span>
<input type="text" name="slug" class="block w-full @error('slug') border-red-500 @enderror mt-1 rounded-md"
placeholder="" value="{{old('slug')}}" />
</label>
@error('slug')
<div class="text-sm text-red-600">{{ $message }}</div>
@enderror
</div>
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Tag</span>
<select name="tags[]" class="block w-full mt-1" multiple>
@foreach ($tags as $tag)
<option value="{{ $tag->id }}">{{ $tag->name }}</option>
@endforeach
</select>
</label>
</div>
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Description</span>
<textarea " class="block w-full mt-1 rounded-md " name="description"
rows="3">{{old('description')}}</textarea>
</label>
@error('description')
<div class="text-sm text-red-600">{{ $message }}</div>
@enderror
</div>
<button type="submit" class="text-white bg-blue-600 rounded text-sm px-5 py-2.5">Submit</button>
</form>
Show Posts Tags
views/posts/index.blade.php
<table class="w-full text-sm text-left text-gray-500">
<thead class="text-xs text-gray-700 uppercase bg-gray-50">
<tr>
<th scope="col" class="px-6 py-3">
#
</th>
<th scope="col" class="px-6 py-3">
Name
</th>
<th scope="col" class="px-6 py-3">
Tags
</th>
</tr>
</thead>
<tbody>
@foreach ($posts as $post)
<tr class="bg-white border-b">
<th scope="row" class="px-6 py-4 font-medium text-gray-900">
{{ $post->id }}
</th>
<td class="px-6 py-4">
{{ $post->title }}
</td>
<td class="px-6 py-4">
@foreach ($post->tags as $tag)
{{ $tag->name }}
@endforeach
</td>
</tr>
@endforeach
</tbody>
</table>