Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jmacdiarmid's avatar

How to seed posts with tags in Laravel 9

I'm working on a simple blog example. The following code is what I'm currently using to seed posts with tags which appears to work. I'm looking for confirmation on this is the most efficient way. Is there a way to attach the tags as each posts is created and saved?

Posts Table

 Schema::create('tags', static function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('slug')->nullable();
            $table->text('description')->nullable();
            $table->softDeletes();
            $table->timestamps();
        });

Tags Table

        Schema::create('tags', static function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('slug')->nullable();
            $table->text('description')->nullable();
            $table->softDeletes();
            $table->timestamps();
        });

Post_Tag Table

        Schema::create('post_tag', function (Blueprint $table) {
            $table->id();
            $table->foreignId('post_id')->constrained();
            $table->foreignId('tag_id')->constrained();
            $table->timestamps();
        });

PostFactory

public function definition()
    {
        $title = rtrim($this->faker->sentence(random_int(5,10)), '.');
        $slug = Str::slug($title);
        $content = collect($this->faker->paragraphs(random_int(3, 7), true))
            ->map(static function ($item) {
                return $item;
            })->toArray();

        $content = implode($content);

        return [
            'title' => $title,
            'slug' => $slug,
            'content' => $content,
            'is_published' => (boolean) random_int(0,1),
        ];
    }

TagFactory

    public function definition()
    {
        $name = $this->faker->word;
        $slug = Str::slug($name);

        return [
            'name' => $name,
            'slug' => $slug
        ];
    }

DatabaseSeeder.php

       \App\Models\Category::factory(10)->create();
        \App\Models\Tag::factory(10)->create();

        User::factory(3)->create()->each(static function (User $user) {
            $category = Category::all()->random(1)->first();
            $user->posts()
                ->saveMany(Post::factory(random_int(1, 5))->make([
                    'category_id' => $category->id,
                    'user_id' => $user->id,
                ]));
        });

        $users = User::with('posts')->get();
        foreach($users as $user) {
            foreach($user->posts as $post) {
                $tags = Tag::pluck('id','name')->random(random_int(1,5))->toArray();
                $post->tags()->attach($tags);
            }
        }
0 likes
2 replies
vybeauregard's avatar

What you have looks good if you want control over how many tags and want them reused on multiple posts.

There's a magic method (https://laravel.com/docs/9.x/eloquent-factories#has-many-relationships-using-magic-methods ) you could use but that would end up generating x number of tags for each post and you'd lose the scenario where multiple posts share tags between them.

Seeders don't really live in the production environment so "efficiency" shouldn't really be much of a concern. If it gets the job done, roll with it.

1 like
Lumethys's avatar

you shouldn't worry about seeding anyway, it is used only for test purpose, spend extra time honing the seeding is unnecessary

Please or to participate in this conversation.