Skip to content

How to Create Multiple Post Types in Laravel

To create different post types (e.g., Blog and Article) in Laravel with separate tables and URL structures, follow these steps:


1. Create Migrations

Define separate tables for blogs and articles.

Blogs Migration:

php artisan make:migration create_blogs_table
// database/migrations/YYYY_MM_DD_create_blogs_table.php
Schema::create('blogs', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->string('slug')->unique(); // For SEO-friendly URLs
    $table->text('content');
    $table->timestamps();
    $table->softDeletes();
});

Articles Migration:

php artisan make:migration create_articles_table
// database/migrations/YYYY_MM_DD_create_articles_table.php
Schema::create('articles', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->string('slug')->unique();
    $table->text('content');
    $table->timestamps();
    $table->softDeletes();
});

Run migrations:

php artisan migrate

2. Create Models

Generate models for Blog and Article.

Blog Model:

php artisan make:model Blog
// app/Models/Blog.php
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Blog extends Model {
    use SoftDeletes;

    protected $fillable = ['title', 'slug', 'content'];

    // Use 'slug' instead of 'id' in URLs
    public function getRouteKeyName() {
        return 'slug';
    }
}

Article Model:

php artisan make:model Article
// app/Models/Article.php
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Article extends Model {
    use SoftDeletes;

    protected $fillable = ['title', 'slug', 'content'];

    public function getRouteKeyName() {
        return 'slug';
    }
}

3. Define Routes

Set up distinct URL structures in routes/web.php:

// Blogs
Route::prefix('blogs')->group(function () {
    Route::get('/', [BlogController::class, 'index'])->name('blogs.index');
    Route::get('/create', [BlogController::class, 'create'])->name('blogs.create');
    Route::post('/', [BlogController::class, 'store'])->name('blogs.store');
    Route::get('/{blog}', [BlogController::class, 'show'])->name('blogs.show');
});

// Articles
Route::prefix('articles')->group(function () {
    Route::get('/', [ArticleController::class, 'index'])->name('articles.index');
    Route::get('/create', [ArticleController::class, 'create'])->name('articles.create');
    Route::post('/', [ArticleController::class, 'store'])->name('articles.store');
    Route::get('/{article}', [ArticleController::class, 'show'])->name('articles.show');
});

4. Create Controllers

Generate controllers for each post type.

BlogController:

php artisan make:controller BlogController --resource
// app/Http/Controllers/BlogController.php
use App\Models\Blog;
use Illuminate\Http\Request;

class BlogController extends Controller {
    public function index() {
        $blogs = Blog::latest()->get();
        return view('blogs.index', compact('blogs'));
    }

    public function show(Blog $blog) {
        return view('blogs.show', compact('blog'));
    }

    public function store(Request $request) {
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'required|string',
        ]);

        // Generate a unique slug
        $slug = str()->slug($request->title);
        $count = Blog::where('slug', $slug)->count();
        if ($count > 0) {
            $slug = $slug . '-' . ($count + 1);
        }

        Blog::create([...$validated, 'slug' => $slug]);

        return redirect()->route('blogs.index');
    }
}

ArticleController:

php artisan make:controller ArticleController --resource
// app/Http/Controllers/ArticleController.php
use App\Models\Article;
use Illuminate\Http\Request;

class ArticleController extends Controller {
    public function index() {
        $articles = Article::latest()->get();
        return view('articles.index', compact('articles'));
    }

    public function show(Article $article) {
        return view('articles.show', compact('article'));
    }

    public function store(Request $request) {
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'required|string',
        ]);

        $slug = str()->slug($request->title);
        $count = Article::where('slug', $slug)->count();
        if ($count > 0) {
            $slug = $slug . '-' . ($count + 1);
        }

        Article::create([...$validated, 'slug' => $slug]);

        return redirect()->route('articles.index');
    }
}

5. Create Views

Organize views into separate directories for clarity.

Blogs Index (resources/views/blogs/index.blade.php):

@foreach ($blogs as $blog)
    <a href="{{ route('blogs.show', $blog) }}">{{ $blog->title }}</a>
@endforeach

Articles Index (resources/views/articles/index.blade.php):

@foreach ($articles as $article)
    <a href="{{ route('articles.show', $article) }}">{{ $article->title }}</a>
@endforeach

Blog Show Page (resources/views/blogs/show.blade.php):

<h1>{{ $blog->title }}</h1>
<p>{{ $blog->content }}</p>

Article Show Page (resources/views/articles/show.blade.php):

<h1>{{ $article->title }}</h1>
<p>{{ $article->content }}</p>

6. Test the URLs

  • Blogs: http://yourapp.com/blogs/my-first-blog
  • Articles: http://yourapp.com/articles/my-first-article

Key Notes:

  1. Slug Uniqueness: Use a package like spatie/laravel-sluggable to automate slug generation.
  2. Shared Logic: Extract common functionality (e.g., slug generation) into traits or parent controllers.
  3. Route Model Binding: Use slug instead of id by overriding getRouteKeyName() in models.

This approach ensures clean separation between post types while maintaining scalability.

Latest Posts

how-to-improve-on-page-seo-on-the-website-by-using-e-e-a-t/

How to Improve On-Page SEO on the Website by Using E-E-A-T

In the ever-evolving landscape of search engine optimization, Google’s E-E-A-T (Experience, Expertise, Authoritativeness, and Trustworthiness) guidelines have become
Phone
Skype
Email
WhatsApp
WhatsApp
Phone
Email
Skype