Laravel is a PHP web application framework with an expressive, elegant syntax. It has a vast library of packages and handles much of the drudge work in programming, leaving you to focus on your creativity.

One creative use for Laravel is the construction of a personal blog. This tutorial describes how to use Laravel to build and publish a blog on Kinsta.

For a preview of the project, check out the complete project code.

Prerequisites

To follow this tutorial, ensure you have the following:

  • A web server. This tutorial uses XAMPP.
  • An account on GitHub, GitLab, or Bitbucket for publishing your application’s code.
  • Laravel installed.
  • An active MyKinsta account for application hosting. Sign up for a free trial if you don’t already have one.

Ensure that the Apache and MySQL module services are running in the XAMPP Control Panel. If not, click each service’s Start button in the Actions column. Your XAMPP Control Panel should look like this:

The XAMPP Control Panel display shows various module services.
XAMPP Control Panel

By default, MySQL/MariaDB runs on port 3306. Take note of the port if you change it.

If you use a web server other than XAMPP, ensure you are running Apache or other server software and have installed MariaDB server on your local machine.

Quickstart With phpMyAdmin

  1. With MySQL and Apache running, head to your browser.
  2. Open phpMyAdmin and paste in http://localhost/phpmyadmin/. It should display the following:
phpMyAdmin opened in the browser.
phpMyAdmin opened in the browser.

phpMyAdmin is a database management tool for MySQL and MariaDB.

Create a New Laravel Project

You can now start creating the blog using Laravel. For this tutorial, we used a computer running on Windows.

  1. Go to your machine’s terminal or command line interface (CLI).
  2. Create a Laravel project called blog using the laravel new blog command.
  3. Open your project’s blog directory with the command cd blog.
  4. Then, open the directory in your code editor.
  5. To check that you built the project successfully, run php artisan serve in your terminal or CMD.
  6. Click the local address output to serve it to the browser. The browser should display the default Laravel Welcome page, shown below:
Laravel Welcome page when served to the browser
Laravel Welcome page

Configure the Database

Create and configure the database by returning to phpMyAdmin in your browser and creating a database called blog.

  1. To create the database, on the Databases tab, type “blog” in the Create database field.
  2. Then, click Create.
Database creation in phpMyAdmin panel
Database creation in phpMyAdmin panel
  1. Next, update the database connection to your .env file at the root of your blog project. Change the DB_DATABASE and DB_PASSWORD values to the ones you created.

The connection details should look like this:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=blog
DB_USERNAME=your-db-username
DB_PASSWORD=your-db-password

The other database connection details remain the same as in the .env file. If you change any connection value, such as changing DB_PORT from 3306 to 3307 during configuration, ensure to update it in the .env file.

Make the Posts Table

Next, create a database model and migrate the changes.

  1. In your terminal, run php artisan make:model Post -mc to create a model called Post, a table called posts, a migration file, and a controller.
Creating a model, a migration file, and a controller through the command line.
Creating a model, a migration file, and a controller through the command line.
  1. Check the database/migrations directory and open the migration file you just created. It has the following format: YYYY_MM_DD_ID_create_posts_table.php.
  2. In the up() method of the migration file, create a schema with title, description, and image attributes.
public function up() {
  Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->string('title')->nullable();
    $table->text('description')->nullable();
    $table->string('image')->nullable();
    $table->timestamps();
  });
}
  1. Now, go to your terminal and migrate the changes using php artisan migrate, as shown below:
Laravel database migration
Laravel database migration
  1. Go to phpMyAdmin in your browser, where you will see the posts table:
The migrated posts table is displayed in phpMyAdmin
The migrated posts table is displayed in phpMyAdmin

How To Create Controllers

Adding views and controllers implements your business logic for the database set. The views are the user interfaces that display data objects from the model. Controllers manage the flow of data execution between the model and views.

  1. Before creating Blade files, run npm install, followed by npm run dev in your terminal. The first command installs the required npm packages. The second command starts a Vite development server.
  2. Head to the app/Http/Controllers directory, open the PostController.php file, and create an index controller method. The controller method renders a simple text to the browser. To do so, add the following code to the PostController class:
public function index() {
  $post = "Laravel Tutorial Series One!";
  return view('posts.index', ['post'=>$post]);
}

This method passes $post as a context variable to the views section of the index Blade template. $post contains text to display, which, here, says, “Laravel Tutorial Series One!” You will replace this with the loop through the posts later.

  1. Create two new directories in the resources/views directory: layouts and posts.
  2. Inside the layouts directory, create an app.blade.php file. Other Blade files will inherit from it.
  3. Copy this code into app.blade.php:
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Blog</title>
  <!-- Styles →
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
  @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>

<!-- Navbar →
<header>
  <nav class="navbar bg-primary">
    <div class="container-fluid">
      <a class="navbar-brand" href="{{ route('posts.index') }}">Mini-Blog</a>
    </div>
  </nav>
</header>

<!-- Body -->
<body>
  @yield('content')
</body>

<!-- Footer -->
<footer class="footer mt-auto py-3 bg-dark">
  <div class="container d-lg-flex justify-content-between">
    <span class="text-light">Mini-Blog © 2023</span>
  </div>
</footer>

<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"  integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
</html>

By using this HTML code, you import Bootstrap version 5.2.3 and Vite to bundle the JavaScript and CSS assets. The generated page has a header with a navbar and a footer with the scripts called below it. In the body, dynamic content renders from other Blade files with the help of @yield('content').

The posts directory holds the Blade files for implementing create and read operations.

  1. Inside the posts directory, create a Blade file called index.blade.php and add the following code:
@extends('layouts.app')
@section('content')
<div class="container">
  <div class="titlebar">
    <h1>Blog list</h1>
  </div>
  <hr>
  <p>The Blog 1 - {{ $post }}</p>
</div>
@endsection

This code extends from the app.blade.php file on the layouts page. When rendered in the browser, it shows the content of each blog post and the navigation bar and footer inherited from the app.blade.php file in the layouts folder. Between the section tags, you pass the content from the controller to render in the browser when you execute the application.

  1. Set the route in the routes directory. Setting the route allows for automatic loading by the RouteServiceProvider in the App/Providers directory. The RouteServiceProvider is the class responsible for loading the application’s route files.
  2. Inside the routes/web.php file, import PostController using use AppHttpControllersPostController.
  3. Then, set the route by adding Route::resource('posts', PostController::class); to the routes/web.php file.
  4. With the Vite development server still running, use php artisan serve to execute the application in your terminal.
  5. With your browser, open http://127.0.0.1:8000/posts to see your new blog post list.

The page should look like the following:

The blog application is displayed in the browser
The blog application is displayed in the browser

In the next section, we define the controller methods for displaying all posts, creating a post, and storing a post. Then, add their routes and create the Blade files in the corresponding sections.

Create the Blog Post Page

Make blog posts by inputting a title, adding a description, and uploading an image. Then, display your posts in sequential order.

  1. In the app/Models directory, open the Post.php file.
  2. In the Post class below the use HasFactory; code block, add protected $fillable = ['title', 'description', 'image'];.

This code protects your model attributes from mass assignments.

  1. In your app/Http/Controllers/PostController.php file, import the Post model using use AppModelsPost;.
  2. Replace the index and create controller methods created earlier in the PostController class with the code below:
// Show all posts
public function index() {
  $posts = Post::orderBy('created_at', 'desc')->get();
  return view('posts.index', ['posts' => $posts]);
}
    
// Create post
public function create() {
  return view('posts.create');
}

In the index method you just created, the PHP application fetches all posts, puts them in chronological order, and then stores them in a posts variable. In the return view, the posts pass into the index.blade.php file as a context variable in the views/posts directory. The create method returns a create.blade.php file and places it in the views/posts directory if a user tries to make a new post.

  1. Create a store controller method using the code below (to store blog posts in the database). Add this code to the PostController class below the index and create controller methods.
// Store post
public function store(Request $request) {
  // validations
  $request->validate([
    'title' => 'required',
    'description' => 'required',
    'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
  ]);

  $post = new Post;

  $file_name = time() . '.' . request()->image->getClientOriginalExtension();
  request()->image->move(public_path('images'), $file_name);

  $post->title = $request->title;
  $post->description = $request->description;
  $post->image = $file_name;

  $post->save();
  return redirect()->route('posts.index')->with('success', 'Post created successfully.');
}

The store method handles client requests regarding the data in its body, so it takes request as an argument. Next, you validate the fields used when creating a post and make a post instance from the Post model. The inputted field data is then assigned to the created instance and saved. The page redirects to the index view with a flash text that says, “Post created successfully.”

Add Routes to Your Posts

To register the routes in your web.php file:

  1. In the routes directory at your project’s root, open the web.php file.
  2. Register the routes of the controller methods by replacing the existing code with this:
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;

Route::resource('/', PostController::class)->names([
  'index' => 'posts.index',
  'create' => 'posts.create',
  'store' => 'posts.store',
  'show' => 'posts.show',
]);

This controller uses these routes to create, store, and display your data objects.

Make Blade Files

To create the views, return to the PostController class:

  1. In the resources/views/posts directory, make a Blade file called create.blade.php and add the code below:
@extends('layouts.app')
@section('content')
<div class="container">
  <h1>Add Post</h1>
  <section class="mt-3">
    <form method="post" action="{{ route('posts.store') }}" enctype="multipart/form-data">
      @csrf
      <!-- Error message when data is not inputted -->
      @if ($errors->any())
        <div class="alert alert-danger">
          <ul>
            @foreach ($errors->all() as $error)
              <li>{{ $error }}</li>
            @endforeach
          </ul>
        </div>
      @endif
      <div class="card p-3">
        <label for="floatingInput">Title</label>
        <input class="form-control" type="text" name="title">
        <label for="floatingTextArea">Description</label>
        <textarea class="form-control" name="description" id="floatingTextarea" cols="30" rows="10"></textarea>
        <label for="formFile" class="form-label">Add Image</label>
        <img src="" alt="" class="img-blog">
        <input class="form-control" type="file" name="image">
      </div>
      <button class="btn btn-secondary m-3">Save</button>
    </form>
  </section>
    
</div>
@endsection

In this code, create.blade.php inherits the contents of app.blade.php in the layouts directory using @extends('layouts.app'). These contents include a header, navigation bar, and footer. After adding the Add Post text within the h1 tag, you created a form with the post method that contains the {{route('posts.store')}} action.

The code enctype="multipart/form-data" allows for image uploads, and csrf protects your form from cross-site attacks. Then, the error messages display invalid field entries and usefield attributes to create labels and inputs for the form.

  1. Now, replace the code in the index.blade.php file with the code below to display all the blog posts:
@extends('layouts.app')
@section('content')
<div class="container">
  <div class="titlebar">
    <a class="btn btn-secondary float-end mt-3" href="{{ route('posts.create') }}" role="button">Add Post</a>
    <h1>Mini post list</h1>
  </div>
    
  <hr>
  <!-- Message if a post is posted successfully -->
  @if ($message = Session::get('success'))
  <div class="alert alert-success">
    <p>{{ $message }}</p>
  </div>
  @endif
         @if (count($posts) > 0)
    @foreach ($posts as $post)
      <div class="row">
        <div class="col-12">
          <div class="row">
            <div class="col-2">
              <img class="img-fluid" style="max-width:50%;" src="{{ asset('images/'.$post->image)}}" alt="">
            </div>
            <div class="col-10">
              <h4>{{$post->title}}</h4>
            </div>
          </div>
          <p>{{$post->description}}</p>
          <hr>
        </div>
      </div>
    @endforeach
  @else
    <p>No Posts found</p>
  @endif
</div>
@endsection

This code adds an Add Post button. When clicked, it creates a post and passes any data into the page’s body. The if condition checks if there is data in the database. If there is data, it passes. If not, it displays “No Posts found.”

Structure Your Pages

You can now run your application using php artisan serve to create and display blog posts. Open <a href="http://127.0.0.1:8000">http://127.0.0.1:8000</a >, and the page should look like this:

The blog application appears in the browser
The blog application appears in the browser

If you add a post, it appears like this:

The blog application displays a post in the browser
The blog application displays a post in the browser

Deploy Your Laravel Blog to Kinsta

To deploy and test your Laravel application using Kinsta’s Application Hosting service:

  1. Create a .htaccess file.
  2. Push the code to a repository.
  3. Create a database.
  4. Set up a project on MyKinsta.
  5. Build and deploy your blog.

Create an .htaccess File

In the project’s root folder, create a file called .htaccess, and add the following code:

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteRule ^(.*)$ public/$1 [L]
</IfModule>

This code redirects your application requests to public/index.php in the deployment.

Push Your Code to a Repository

Create a repository for your project and publish the code. You can use GitHub, GitLab, or Bitbucket to host your code and deploy it to MyKinsta.

Set Up the Database in Your MyKinsta Dashboard

To create a database on MyKinsta:

  1. Click the Add Service button and select Database.
  2. Enter the details of your database as shown below. Note that for your deployment to be successful, you must leave the Database username as the default value.
Creating a database in MyKinsta
Creating a database in MyKinsta

The details include the Database name, Display name, Database type, Version, Database username, Data center location, and Size. This demonstration uses MariaDB for the database, and the Size is Db3 (1CPU / 4GB RAM / 10GB Disk Space 65 USD / month). You can choose the database type and size that suits your specific needs.

  1. Click Continue.
  2. Confirm your monthly cost and payment method, then click Create database.

Set Up the Project on MyKinsta

To deploy your application to MyKinsta:

  1. Click the Dashboard panel.
  2. Click Add Service and select Application, as shown below:
MyKinsta dashboard when adding application service
MyKinsta dashboard when adding application service

MyKinsta redirects you to the Add Application page.

  1. In the Select branch card section, select your GitHub repository, then select the Add deployment on commit checkbox.
  2. In the Basic details, input the application name and select the data center location for your application.
  3. Since Laravel needs an app key during deployment, in the Environment variables card, add an APP_KEY as Key 1. You can use the APP_KEY defined in your local .env file or use an online Laravel Key generator to get one.
  4. Click Continue.
  5. Select the build resources (CPU and RAM) for your application. This demonstration uses the standard build machine (1CPU / 4 GB RAM) – 0.02USD / minute.
  6. Leave the Set up container image automatically radio button selected.
  7. Click Continue.
  8. In the Set up your processes page, you can change your application’s pod size and instance by selecting these boxes. This demonstration uses the default values.
  9. Click Continue.
  10. Finally, click the Confirm payment method button to start your application’s deployment. Clicking this also directs you to the Deployment details page to view the progress of your deployment.

Build and Deploy Your Application

With the database and application hosted, connect the database to your application and build to deploy.

To connect the database, use the external connections of your hosted database. On the Info tab of your hosted database, you see External connections, as shown below:

External connections for your hosted database
External connections for your hosted database
  1. On the deployed app’s Settings page, navigate to the Environment variable card.
  2. Click Add environment variable to add the external connections of your hosted database with the corresponding value. Use the same variables you have in your .env file.
The environment variables for your hosted database
The environment variables for your hosted database

This screenshot is handy if you consider marking the <code>env</code> variables you edited manually to differentiate them from the others.

The APP_URL is the URL of your hosted application, and DB_CONNECTION is mysql.

  1. Head to your application’s Settings page.
  2. In the Buildpack card, add PHP and Node.js as build packs. Since this is a PHP application, you must add the PHP build pack last.
  3. Click Deploy now to rebuild your application.

Next, add a process that will migrate the database.

  1. Head to the Processes tab on your hosted application page.
  2. Select Create process on the Runtime processes card.
  3. Enter Migration as the name, Background worker as the type, and php artisan migrate --force as a start command. You can leave the pod size and instances with the default values.
  4. Select Continue to create the process. This action triggers a new build and redeploys the application.
  5. On the Domains tab of your application, click your application link. You can see that it’s now up and running.
  6. Note that the blog application deployed to MyKinsta displays no posts. Create a new post by inputting its title, adding a description, and choosing an image.

Summary

Laravel makes it easy to develop a simple blog quickly. Its rapid page loading, robust controller architecture, and competent security make enhancing an application’s performance easy. Meanwhile, MyKinsta lets you release and ship your web applications quickly and effectively. MyKinsta’s flexible pricing model is based on usage, eliminating hidden costs.

When Kinsta hosts your Laravel application, it runs on the Google Cloud Platform on their Premium Tier, making it as fast as possible. Kinsta also includes enterprise-level DDoS protection and mitigation with Cloudflare and advanced firewalls to keep malicious actors at bay and much more.

Start your Application Hosting free trial right now to streamline your web application development and hosting!

Marcia Ramos Kinsta

I'm the Editorial Team Lead at Kinsta. I'm a open source enthusiast and I love coding. With more than 7 years of technical writing and editing for the tech industry, I love collaborating with people to create clear and concise pieces of content and improve workflows.