More Tutorials on Web Development
Table of Contents
Registering Routes
use App\Http\Controllers\CategoryController;
use App\Http\Controllers\IndexController;
use App\Http\Controllers\PostController;
use App\Http\Controllers\TagController;
Route::get('/', IndexController::class);
Route::get('/category/{slug}', CategoryController::class);
Route::get('/tag/{slug}', TagController::class);
Route::get('/post/{slug}', [PostController::class, 'show']);
We didn’t use the single-action controller for the post controller because we are going to add a search
function here in the next article.
For now, your IDE will probably give you an error, because we haven’t created these controllers yet.
Controllers
Index Controller
<?php
namespace App\Http\Controllers;
use App\Models\General;
use App\Models\Post;
use App\Models\Tag;
use App\Models\Category;
use Illuminate\Http\Request;
class IndexController extends Controller
{
public function __invoke()
{
//get the general information about the website
$website = General::query()->firstOrFail();
//get the posts that are published, sort by decreasing order of "id".
$posts = Post::query()
->where('is_published',true)
->orderBy('id','desc')
->get();
//get the featured posts
$featured_posts = Post::query()
->where('is_published',true)
->where('is_featured',true)
->orderBy('id','desc')
->take(5)
->get();
//get all the categories
$categories = Category::all();
//get all the tags
$tags = Tag::all();
//get the recent 5 posts
$recent_posts = Post::query()
->where('is_published',true)
->orderBy('created_at','desc')
->take(5)
->get();
//return the data to the corresponding view
return view('home', [
'website' => $website,
'posts' => $posts,
'featured_posts' => $featured_posts,
'categories' => $categories,
'tags' => $tags,
'recent_posts' => $recent_posts
]);
}
}
Category Controller
<?php
namespace App\Http\Controllers;
use App\Models\General;
use App\Models\Post;
use App\Models\Tag;
use App\Models\Category;
use Illuminate\Http\Request;
class CategoryController extends Controller
{
public function __invoke($slug)
{
//get the general information about the website
$website = General::query()->firstOrFail();
//get the requested category
$category = Category::query()
->where('slug', $slug)
->firstOrFail();
//get the posts in that category
$posts = $category->posts()
->where('is_published',true)
->orderBy('id','desc')
->get();
//get all the categories
$categories = Category::all();
//get all the tags
$tags = Tag::all();
//get the recent 5 posts
$recent_posts = Post::query()
->where('is_published',true)
->orderBy('created_at','desc')
->take(5)
->get();
//return the data to the corresponding view
return view('category', [
'website' => $website,
'category' => $category,
'posts' => $posts,
'categories' => $categories,
'tags' => $tags,
'recent_posts' => $recent_posts
]);
}
}
Tag Controller
<?php
namespace App\Http\Controllers;
use App\Models\General;
use App\Models\Post;
use App\Models\Tag;
use App\Models\Category;
use Illuminate\Http\Request;
class TagController extends Controller
{
public function __invoke($slug)
{
//get the general information about the website
$website = General::query()->firstOrFail();
//get the requested tag
$tag = Tag::query()
->where('slug', $slug)
->firstOrFail();
//get the posts with that tag
$posts = $tag->posts()
->where('is_published',true)
->orderBy('id','desc')
->get();
//get all the categories
$categories = Category::all();
//get all the tags
$tags = Tag::all();
//get the recent 5 posts
$recent_posts = Post::query()
->where('is_published',true)
->orderBy('created_at','desc')
->take(5)
->get();
//return the data to the corresponding view
return view('tag', [
'website' => $website,
'tag' => $tag,
'posts' => $posts,
'categories' => $categories,
'tags' => $tags,
'recent_posts' => $recent_posts
]);
}
}
Post Controller
<?php
namespace App\Http\Controllers;
use App\Models\General;
use App\Models\Post;
use App\Models\Tag;
use App\Models\Category;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function show($slug)
{
//get the general information about the website
$website = General::query()->firstOrFail();
//get the requested post, if it is published
$post = Post::query()
->where('is_published', true)
->where('slug', $slug)
->firstOrFail();
//get all the categories
$categories = Category::all();
//get all the tags
$tags = Tag::all();
//get the recent 5 posts
$recent_posts = Post::query()
->where('is_published', true)
->orderBy('created_at', 'desc')
->take(5)
->get();
//return the data to the corresponding view
return view('post', [
'website' => $website,
'post' => $post,
'categories' => $categories,
'tags' => $tags,
'recent_posts' => $recent_posts,
]);
}
}
Views
In this tutorial, we will be using this Bootstrap template for our views.

You can download the source code here:
Assuming you understand how HTML, CSS and JS work. This is the view structure I designed:
Layout
- views
- vendor
- posts-list.blade.php
- sidebar.blade.php
- master.blade.php
- home.blade.php
- category.blade.php
- tag.blade.php
- post.blade.php
- vendor
Master
<!DOCTYPE html>
<html lang="en">
<head>
@yield('meta')
@yield('title')
<!-- Bootstrap core CSS -->
<link href="{{asset('vendor/bootstrap/css/bootstrap.css')}}" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="{{asset('vendor/css/mystyle.css')}}" rel="stylesheet">
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
<div class="container">
<a class="navbar-brand" href="/">{{$website['website_title']}}</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive"
aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item active">
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://www.techjblog.com/index.php/laravel-tutorial-for-beginners/">Laravel
Tutorial</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/nova">Admin</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- Page Content -->
<div class="container">
@yield('content')
</div>
<!-- /.container -->
<!-- Footer -->
<footer class="py-5 bg-dark">
<div class="container">
<p class="m-0 text-center text-white">Copyright
© {{$website['website_title']}} <?php echo date("Y"); ?></p>
</div>
<!-- /.container -->
</footer>
<!-- Bootstrap core JavaScript -->
<script src="{{asset('vendor/bootstrap/js/jquery/jquery.min.js')}}"></script>
<script src="{{asset('vendor/bootstrap/js/bootstrap.bundle.min.js')}}"></script>
</body>
</html>
Line 11, {{asset('vendor/css/bootstrap.min.css')}}
generates the URL /public/vendor/css/bootstrap.min.css
.
Post List
@foreach($posts as $post)
<!-- Blog Post -->
<div class="card mb-4">
<img class="card-img-top" src="{{\Illuminate\Support\Facades\Storage::url($post['featured_image'])}}" alt="Card image cap">
<div class="card-body">
<h2 class="card-title">{{$post['title']}}</h2>
<p class="card-text">{{\Illuminate\Support\Str::limit(strip_tags($post['content']), 200, '...')}}</p>
<a href="/post/{{$post['slug']}}" class="btn btn-primary">Read More →</a>
</div>
<div class="card-footer text-muted">
Posted on {{$post->created_at->format('M d Y')}} by
<a href="#">{{$post->user['name']}}</a>
</div>
</div>
@endforeach
Line 7, strip_tags()
will eliminate the HTML tags, \Illuminate\Support\Str::limit()
can limit the number of characters that are shown, in this case, limit the string to 200 char and end with “...
“
Line 11, format('M d Y')
changes the format of the date.
Sidebar
<!-- Sidebar Widgets Column -->
<div class="col-md-4">
<!-- Search Widget -->
<div class="card my-4">
<h5 class="card-header">Search</h5>
<form class="card-body" action="" method="GET" role="search">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search for..." name="q">
<span class="input-group-btn">
<button class="btn btn-secondary" type="submit">Go!</button>
</span>
</div>
</form>
</div>
<a href="https://www.techjblog.com/index.php/tutorials/laravel-tutorial-9-search-pagination-related-posts-and-other-functions/#0-search/">How
to Add Search Function for Your Blog</a>
<!-- Categories Widget -->
<div class="card my-4">
<h5 class="card-header">Categories</h5>
<div class="card-body">
<div class="row">
<div class="col-lg-6">
<ul class="list-unstyled mb-0">
@foreach($categories as $category)
<li>
<a href="/category/{{$category['slug']}}">{{$category['name']}}</a>
</li>
@endforeach
</ul>
</div>
</div>
</div>
</div>
<!-- Tags Widget -->
<div class="card my-4">
<h5 class="card-header">Tags</h5>
<div class="card-body">
<div class="row">
<div class="col-lg-6">
<ul class="list-unstyled mb-0">
@foreach($tags as $tag)
<li>
<a href="/tag/{{$tag['slug']}}">{{$tag['name']}}</a>
</li>
@endforeach
</ul>
</div>
</div>
</div>
</div>
<!-- Recent Posts Widget -->
<div class="card my-4">
<h5 class="card-header">Recent Posts</h5>
<div class="card-body">
<div class="row">
<div class="col-lg-12">
<ul class="list-unstyled mb-0">
@foreach($recent_posts as $post)
<li>
<a href="/post/{{$post['slug']}}">{{$post['title']}}</a>
</li>
<hr>
@endforeach
</ul>
</div>
</div>
</div>
</div>
<!-- Side Widget -->
<div class="card my-4">
<h5 class="card-header">Tutorial</h5>
<div class="card-body">
<ul class="list-unstyled mb-0">
<li>
<a href="https://www.techjblog.com/index.php/laravel-tutorial-for-beginners/">Laravel Tutorial For
Beginners</a>
</li>
</ul>
</div>
</div>
</div>
Home Page
@extends('master')
@section('meta')
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="{{$website['description']}}">
<meta name="author" content="Eric Hu">
@endsection
@section('title')
<title>{{$website['website_title']}}</title>
@endsection
@section('content')
<div class="row">
<!-- Blog Entries Column -->
<div class="col-md-8">
<h1 class="my-4">Laravel Blog
<small>Home Page</small>
</h1>
@include('vendor.posts-list')
</div>
@include('vendor.sidebar')
</div>
@endsection
Category Page
@extends('master')
@section('meta')
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="{{$website['description']}}">
<meta name="author" content="Eric Hu">
@endsection
@section('title')
<title>{{$website['website_title']}} - Category:{{$category['name']}}</title>
@endsection
@section('content')
<div class="row">
<!-- Blog Entries Column -->
<div class="col-md-8">
<h1 class="my-4">Category:
<small>{{$category['name']}}</small>
</h1>
@include('vendor.posts-list')
</div>
@include('vendor.sidebar')
</div>
@endsection
Tag Page
@extends('master')
@section('meta')
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="{{$website['description']}}">
<meta name="author" content="Eric Hu">
@endsection
@section('title')
<title>{{$website['website_title']}} - Tag:{{$tag['name']}}</title>
@endsection
@section('content')
<div class="row">
<!-- Blog Entries Column -->
<div class="col-md-8">
<h1 class="my-4">Tag:
<small>{{$tag['name']}}</small>
</h1>
@include('vendor.posts-list')
</div>
@include('vendor.sidebar')
</div>
@endsection
Post Page
@extends('master')
@section('meta')
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="{{$website['description']}}">
<meta name="author" content="Eric Hu">
@endsection
@section('title')
<title>{{$post['title']}}{{$website['website_title']}}</title>
@endsection
@section('content')
<div class="row">
<!-- Post Content Column -->
<div class="col-lg-8">
<!-- Title -->
<h1 class="mt-4">{{$post['title']}}</h1>
<!-- Author -->
<p class="lead">
by
<a href="#">{{$post->user['name']}}</a>
</p>
<hr>
<!-- Date/Time -->
<p>Posted on {{$post->created_at->format('M d, Y')}}</p>
<hr>
<!-- Preview Image -->
<img class="img-fluid rounded" src="{{\Illuminate\Support\Facades\Storage::url($post->featured_image)}}" alt="">
<hr>
<!-- Post Content -->
{!! $post->content !!}
<hr>
</div>
@include('vendor.sidebar')
</div>
@endsection
Line 39, {!! $post->content !!}
get the content for the post. {!! !!}
must be used or the HTML tags will not work.
By default, Blade {{ }}
statements are automatically sent through PHP’s htmlspecialchars
function to prevent XSS attacks.