How to build a blog application using Laravel 11 with bootstrap 5
Using Laravel 11 to build blog application with Vite and Bootstrap 5 as the frontend
Table of contents
In this article, I will demonstrate how to build a blog application using Laravel 11 with Bootstrap 5 for the frontend. This is an upgraded version of the previous article titled : Laravel 9: Building a blog application with Bootstrap 5
At the end of this tutorial you'll be able to:
Use the new Laravel 11 to build applications
Understand how to plan a web application development
Use Laravel models
Create migration, model, controller using Laravel Artisan command
Use Laravel Controller, Routes etc....
I’ll continue with this Project from my previous video on Laravel fortify for the authentication part of the application.
Let's begin building the blog application ....
Posts Table Migrations
The first is to decide what records to collect and how to store the user blog post in the database. Let's create a posts table to keep record of posts for our blog.
Using the Laravel artisan command in the terminal:
php artisan make:Model Post -m
This will create a Post model with the corresponding migration file for the blog post table called posts.
If you already have a Model you can use the Artisan command below to create a posts migration.
php artisan make:migration create_posts_table --create=posts
Update the posts migration file
Open the posts table migration file to add the following columns:
ulid (initially uuid was used but ulid is now common because it is smaller compared to uuid that is 128bits. The reason for ulid is to ensure we don't add the table id to the website link.
user_id (to associate with the owner of the post)
post title
post content
post status
$table->id();
$table->ulid()->unique();
$table->unsignedBigInteger('user_id');
$table->string('title');
$table->text('content');
$table->boolean('status')->default(1);
$table->timestamps();
Feel free to extend the columns according to the need of your blog project.
Run the Migrate Command
After adding the necessary columns to the posts file run the migrate artisan command:
php artisan migrate
Create HasUlid Trait
Since we're using ulid we need to create a HasUlid trait to populate the ulid column of the model where it is included.
Create a Trait Folder in the app folder and create a HasUlid.php file
- HasUlid.php
<?php
namespace App\Traits;
use Illuminate\Support\Str;
trait HasUlid
{
protected static function boot()
{
//The boot method is used to hook into the model's lifecycle events.
parent::boot();
//creating use to set the event for the ulid attribute to be set
static::creating(function ($model) {
//generate a unique ulid value to the model instance when creating a new record
$model->ulid = strtolower((string) Str::ulid());
});
}
}
Update the Post Model
The Post model has to be updated to include the following:
Update the Post model to use the HasUlid trait.
The fillable model property for columns that will receive data.
Define the belongsTo relationship of the user_id foreign key to users table. The user() method can be used to retrieve the details of the user associated with a post.
<?php
namespace App\Models;
use App\Traits\HasUlid;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Post extends Model
{
use HasFactory, HasUlid;
public $fillable = [
'title',
'content',
'ulid',
'status'
];
public function user (): BelongsTo {
return $this->belongsTo(User::class);
}
}
Cast Attribute in Laravel Model
you may define an accessor and mutator using a single, non-prefixed method by type-hinting a return type of Illuminate\Database\Eloquent\Casts\Attribute:
Update the Post model to cast the created_at to be human readable or format the value to be stored in the database.
public function createdAt(): Attribute
{
return new Attribute(
//accessor to transform the value when it is accessed
get: fn ($value) => Carbon::parse($value)->diffForHumans(),
//you can also use set to mutate the value
);
}
Update the User model
Define a HasMany relationship to the posts table in the User model. With this method we can retrieve the post(s) belonging to a user as the author.
public function posts(): HasMany {
return $this->hasMany(Post::class);
}
Views for the posts
Before delving further let's setup the frontend of the blog post management.
This video video where i demo how to setup authentication system covers bootstrap 5 setup also using vite. We'll use a free blog template from startbootstrap for some of the posts pages.
The views covers the demo for the Post management (index, create, edit, show), Including form validations errors, the home (to list all the posts) & welcome page.
Create the PostController
We'll create a resource controller named PostController.
The make:controller command is used to generate controller in Laravel. Since we want to perform a full crud we'll add the --resource flag to generate the index, create, store, update, show and delete method in the PostController.
php artisan make:controller PostController --resource
OR
php artisan make:controller PostController -r
php artisan make:model Post -a
OR
//you can define what your model name should be
php artisan make:controller PostController --resource --model=Post
OR
//generates resource with a model with Post as the name of the
//model automatically
php artisan make:controller PostController -rm
Here's the PostController. We have an additional method called all_posts to display all posts:
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
//returns all post belonging to the logged in user that is an author
$posts = Post::where('user_id', auth()->id())->latest()->get();
return view('posts.index', ['posts' => $posts]);
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//returns the page containing the form for creating blog post
return view('posts.create');
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|string|min:3|max:255',
'content' => 'required|string|min:10',
]);
$user = auth()->user();
$user->posts()->create($validated);
return redirect()->route('posts.create')
->with('success', 'Post created successfully.');
}
/**
* Display the specified resource.
*/
public function show(string $ulid)
{
//display a single post for detialed view
$post = Post::where('ulid', $ulid)->firstOrFail();
return view('posts.show', ['post' => $post]);
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $ulid)
{
//return view for the editing of a blog post
$post = Post::where('ulid', $ulid)->firstOrFail();
return view('posts.edit', ['post' => $post]);
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $ulid)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string',
]);
$post = Post::where('ulid', $ulid)->firstOrFail();
$post->update($validated);
return redirect()->route('posts.index')
->with('success', 'Post updated successfully');
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $ulid)
{
//delete a blog post
$post = Post::where('ulid', $ulid)->firstOrFail();
$post->delete();
return redirect()->route('posts.index')
->with('success', 'Post deleted!!!');
}
public function all_posts()
{
$posts = Post::latest()->get();
return view('welcome', compact('posts'));
}
}
Define Routes
Define routes to access different part of the blog application. Head over to the web.php file in the routes folder.
We'll use the controller value for the group method to define the common controller for all of the routes within the group. Then, when defining the routes, you only need to provide the controller method that they invoke:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
//display all post for unauthenticated users
Route::controller(PostController::class)->group(function () {
Route::get('/', 'all_posts');
});
//only authenticated and verified users can see manage posts as authors
Route::middleware(['auth', 'verified'])->group(function () {
//resource for posts urls
Route::resource('posts', PostController::class);
});
Use the Route Artisan command to confirm the route list in your application
php artisan route:list
Serve the App
php artisan serve
AND
npm run dev
Demo
- Welcome Page
- Add Post
- User blog post
- Show post details
If logged in user is the author show edit and delete
In real-world applications ensure to make use of the soft delete for a delete action and also confirm the action from the user just in a case of unintended click.
Conclusion
In this article, we've covered how to build a blog application using Laravel 11.