Laravel 9 Posts with Tags Many to Many Relationships Example

In this tutorial we will see how to add tags in posts using many to many relationships.


Create Post Modal Migration Controller and Route

run below command to create post modal, 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();
    });
}

web.php

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 Post Controller

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

laravel 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>
laravel 9 many to many tags example

laravel 9 many to many tags example


Tags: