Laravel Posts with Tags Many to Many Relationships Example

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>
many to many tags store

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>
many to many tags example
saim ansari
saim ansari

I'm Saim Ansari, a full-stack developer with 4+ years of hands-on experience who thrives on building web applications that leave a lasting impression. When it comes to tech, I'm particularly adept at Laravel, React, Tailwind CSS, and the Tall Stack