Scroll Top

Building a Laravel Blog: A Complete Guide from Scratch

laravel blog system

Well, effective writing is an essential skill that helps individuals to communicate their ideas and expertise with global audiences. With so, blogging has evolved into an crucial medium for both personal expression and professional growth. This allows people to share their unique perspectives and establish their online presence. So, in this comprehensive tutorial, we’ll learn how to create a full-featured Laravel blog system. By the end, you’ll have a professional blog platform with all essential features.

Let’s start now…!!

Developing Laravel Blog Page From Scratch

Here is what we want to achieve through this guide:

Laravel blog page example

Step 1: Setting the Foundation

Every great project begins with the basics. Let’s start by creating a Laravel application.If you’d rather hand that setup to a specialist, many teams bring in dedicated Laravel development services to get the foundation right from day one

Run the following command to create your project:

composer create-project --prefer-dist laravel/laravel blog

Once that’s done, navigate into the project directory:

cd blog

Before moving forward, configure your .env file with the appropriate database credentials. Now let’s install Tailwind CSS, which we’ll use to make our blog look modern and responsive:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init

Update your tailwind.config.js file to scan Laravel’s resources/views for classes:

module.exports = {
  content: [
    './resources/**/*.blade.php',
    './resources/**/*.js',
    './resources/**/*.html',
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};

Finally, add the Tailwind directives to your CSS file at resources/css/app.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

// basic style 
/* Basic editor styles */
.tiptap {
    :first-child {
        margin-top: 0;
    }

    /* List styles */
    ul,
    ol {
        padding: 0 1rem;
        margin: 1.25rem 1rem 1.25rem 0.4rem;

        li p {
            margin-top: 0.25em;
            margin-bottom: 0.25em;
        }
    }
    
    ul{
        list-style-type: disc;
    }

    ol{
        list-style-type: decimal;
    }

    /* Heading styles */
    h1,
    h2,
    h3,
    h4,
    h5,
    h6 {
        line-height: 1.1;
        margin-top: 2.5rem;
        text-wrap: pretty;
    }

    h1,
    h2 {
        margin-top: 3.5rem;
        margin-bottom: 1.5rem;
    }

    h1 {
        font-size: 1.4rem;
    }

    h2 {
        font-size: 1.2rem;
    }

    h3 {
        font-size: 1.1rem;
    }

    h4,
    h5,
    h6 {
        font-size: 1rem;
    }

    /* Code and preformatted text styles */
    code {
        background-color: var(--purple-light);
        border-radius: 0.4rem;
        color: var(--black);
        font-size: 0.85rem;
        padding: 0.25em 0.3em;
    }

    pre {
        background: var(--black);
        border-radius: 0.5rem;
        color: var(--white);
        font-family: "JetBrainsMono", monospace;
        margin: 1.5rem 0;
        padding: 0.75rem 1rem;

        code {
            background: none;
            color: inherit;
            font-size: 0.8rem;
            padding: 0;
        }
    }

    blockquote {
        border-left: 3px solid var(--gray-3);
        margin: 1.5rem 0;
        padding-left: 1rem;
    }

    hr {
        border: none;
        border-top: 1px solid var(--gray-2);
        margin: 2rem 0;
    }
    
     &:focus{
        outline: none;
    }
}

Compile the assets:

npm run dev

Step 2: Adding The Backbone of Laravel Blog

Let’s create a Blog model with the necessary migration:

php artisan make:model Blog -m

In the migration file (located in database/migrations), define the structure of the blogs table:

public function up()
{
    Schema::create('blogs', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->text('content');
        $table->timestamps();
    });
}

Run the migration to create the table:

php artisan migrate

Step 3: Setting Up Routes & Controller For Laravel Blog

Blogs need pages! Define routes in routes/web.php:

use App\Http\Controllers\BlogController;

Route::get('/blogs', [BlogController::class, 'index']);
Route::get('/blogs/create', [BlogController::class, 'create']);
Route::post('/blogs', [BlogController::class, 'store']);

Create a BlogController:

php artisan make:controller BlogController

Inside the controller, add the methods to display, create, and store blog posts:

namespace App\Http\Controllers;

use App\Models\Blog;
use Illuminate\Http\Request;

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

    public function create()
    {
        return view('blogs.create');
    }

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

        Blog::create($validated);
        return redirect('/blogs')->with('success', 'Blog created successfully!');
    }
}

Step 4: Creating the Editor with Tiptap

Here comes the fun part: integrating a rich-text editor!

Install TipTap & Extensions:
npm install @tiptap/core @tiptap/starter-kit @tiptap/extension-bold @tiptap/extension-italic @tiptap/extension-heading @tiptap/extension-list-item @tiptap/extension-ordered-list @tiptap/extension-bullet-list @tiptap/extension-link @tiptap/extension-text-align @tiptap/extension-code @tiptap/extension-highlight

Add JavaScript To TipTap

Create resources/js/tiptap.js:

import { Editor } from '@tiptap/core';
import Bold from '@tiptap/extension-bold';
import BulletList from '@tiptap/extension-bullet-list';
import Heading from '@tiptap/extension-heading';
import Italic from '@tiptap/extension-italic';
import Link from '@tiptap/extension-link';
import ListItem from '@tiptap/extension-list-item';
import OrderedList from '@tiptap/extension-ordered-list';
import TextAlign from '@tiptap/extension-text-align';
import '@tiptap/starter-kit';
import StarterKit from '@tiptap/starter-kit';

document.addEventListener('DOMContentLoaded', () => {
    const editor = new Editor({
        element: document.querySelector('#editor'),
        extensions: [
            StarterKit,
            Bold,
            Italic,
            Heading.configure({ levels: [1, 2, 3] }),
            OrderedList,
            BulletList,
            ListItem,
            Link.configure({ openOnClick: true }),
            TextAlign.configure({ types: ['heading', 'paragraph'] }),
        ],
        content: '<p>Start writing...</p>',
    });

    const form = document.querySelector('form');
    const contentField = document.querySelector('#content');

    form.addEventListener('submit', () => {
        contentField.value = editor.getHTML(); // Save editor content to the hidden textarea
    });


     // Add event listeners to the buttons
     document.querySelectorAll('[data-action]').forEach((button) => {
        button.addEventListener('click', () => {
            const action = button.getAttribute('data-action');

            // Perform actions based on the data-action attribute
            switch (action) {
                case 'bold':
                    editor.chain().focus().toggleBold().run();
                    break;
                case 'italic':
                    editor.chain().focus().toggleItalic().run();
                    break;
                case 'heading1':
                    editor.chain().focus().toggleHeading({ level: 1 }).run();
                    break;
                case 'heading2':
                    editor.chain().focus().toggleHeading({ level: 2 }).run();
                    break;
                case 'bulletList':
                    editor.chain().focus().toggleBulletList().run();
                    break;
                case 'orderedList':
                    editor.chain().focus().toggleOrderedList().run();
                    break;
                case 'alignLeft':
                    editor.chain().focus().setTextAlign('left').run();
                    break;
                case 'alignCenter':
                    editor.chain().focus().setTextAlign('center').run();
                    break;
                case 'alignRight':
                    editor.chain().focus().setTextAlign('right').run();
                    break;
                case 'link':
                    const url = prompt('Enter the link URL:');
                    if (url) {
                        editor.chain().focus().setLink({ href: url }).run();
                    }
                    break;
                default:
                    console.warn(`No action defined for: ${action}`);
            }
        });
    });
});

Step 5: Create the Blade Templates

Blog Creation Page

In resources/views/blogs/create.blade.php :

import { Editor } from '@tiptap/core';
import Bold from '@tiptap/extension-bold';
import BulletList from '@tiptap/extension-bullet-list';
import Heading from '@tiptap/extension-heading';
import Italic from '@tiptap/extension-italic';
import Link from '@tiptap/extension-link';
import ListItem from '@tiptap/extension-list-item';
import OrderedList from '@tiptap/extension-ordered-list';
import TextAlign from '@tiptap/extension-text-align';
import '@tiptap/starter-kit';
import StarterKit from '@tiptap/starter-kit';

document.addEventListener('DOMContentLoaded', () => {
    const editor = new Editor({
        element: document.querySelector('#editor'),
        extensions: [
            StarterKit,
            Bold,
            Italic,
            Heading.configure({ levels: [1, 2, 3] }),
            OrderedList,
            BulletList,
            ListItem,
            Link.configure({ openOnClick: true }),
            TextAlign.configure({ types: ['heading', 'paragraph'] }),
        ],
        content: '<p>Start writing...</p>',
    });

    const form = document.querySelector('form');
    const contentField = document.querySelector('#content');

    form.addEventListener('submit', () => {
        contentField.value = editor.getHTML(); // Save editor content to the hidden textarea
    });


     // Add event listeners to the buttons
     document.querySelectorAll('[data-action]').forEach((button) => {
        button.addEventListener('click', () => {
            const action = button.getAttribute('data-action');

            // Perform actions based on the data-action attribute
            switch (action) {
                case 'bold':
                    editor.chain().focus().toggleBold().run();
                    break;
                case 'italic':
                    editor.chain().focus().toggleItalic().run();
                    break;
                case 'heading1':
                    editor.chain().focus().toggleHeading({ level: 1 }).run();
                    break;
                case 'heading2':
                    editor.chain().focus().toggleHeading({ level: 2 }).run();
                    break;
                case 'bulletList':
                    editor.chain().focus().toggleBulletList().run();
                    break;
                case 'orderedList':
                    editor.chain().focus().toggleOrderedList().run();
                    break;
                case 'alignLeft':
                    editor.chain().focus().setTextAlign('left').run();
                    break;
                case 'alignCenter':
                    editor.chain().focus().setTextAlign('center').run();
                    break;
                case 'alignRight':
                    editor.chain().focus().setTextAlign('right').run();
                    break;
                case 'link':
                    const url = prompt('Enter the link URL:');
                    if (url) {
                        editor.chain().focus().setLink({ href: url }).run();
                    }
                    break;
                default:
                    console.warn(`No action defined for: ${action}`);
            }
        });
    });
});

Step 6: View All Blogs

In resources/views/blogs/index.blade.php:

@extends('layout')

@section('content')
<div class="bg-white shadow rounded p-6">
    <h1 class="text-xl font-bold mb-4">Blog Posts</h1>
    @foreach ($blogs as $blog)
        <div class="mb-4">
            <h2 class="text-lg font-semibold">{{ $blog->title }}</h2>
            <div class="prose">{!! $blog->content !!}</div>
        </div>
    @endforeach
</div>
@endsection

Note: The tip-tap editor does not provide a style for your front-end blog page. You will have to style it manually.

Congratulations! You have successfully created a basic blog in your Laravel application.

Key Takeaways:

  • Scalable Approach: Building with Laravel’s extensibility in mind for future features.
  • Strong Foundation: You’ve learned how to scaffold a Laravel project from scratch.
  • Database Integration: Setting up migrations and models for a dynamic application.
  • MVC Structure: Leveraging Laravel’s Model-View-Controller framework for clear code organization.
  • Template Engine: Crafting responsive and dynamic interfaces using Blade.

JetShip: A Laravel Starter Kit With a Pre-Built Blog Page.

JetShip Laravel SaaS Boilerplate

The Jetship Laravel Starter Kit is a robust solution designed to streamline the development of SaaS applications, offering developers a comprehensive set of features and tools to jump-start their projects.

Besides, JetShip SaaS Boilerplate boosts the development process by providing a clean, modular, and scalable foundation for building SaaS platforms.

Additionally, it simplifies the most challenging aspects of SaaS development by offering pre-built components, blocks, and features.

Key Features:

  • Based on FilamentPHP
  • Ready for production
  • Easy Laravel Forge Deployment
  • In Built Blog Page
  • Seamless Authentication
  • Subscriptions & One-Time Purchases
  • Appealing Admin Panel
  • 2-Factor Auth
  • Plugins
  • Customizable & Scalable
  • Mobile Friendly & much more

Built on the TALL stacks:

  • Tailwind CSS
  • Alpine.js
  • Laravel
  • Livewire

Why Choose JetShip?

JetShip laravel SaaS Starter Kit is ideal for developers who want to quickly prototype, launch, and scale their SaaS applications without building everything from scratch.

  • Provides flexibility with multiple themes and customizable blocks, helping you create a unique look for your SaaS product.
  • Offers access to ready-made components for user management, payment gateways, subscriptions, SEO optimization, and much more.
  • It comes with lifetime access to the codebase and regular updates, ensuring your application stays up to date with the latest features and security standards.

Besides, it is a perfect choice for those looking to boost their SaaS app development with Laravel. Moreover, it is built using FlyonUI which is an Open Source Tailwind CSS Components Library, which offers the semantic class with powerful JS plugins.

Want to check the live demo? Then check out the blog page demo.

Conclusion:

Building a blog with Laravel is a great way to understand the fundamentals of this powerful PHP framework. Through this guide, we’ve walked through the process of setting up a Laravel project, designing a database schema, building a user-friendly interface, and implementing essential features like CRUD operations and templates.

By now, you should have a functional blog with the ability to create, read, update, and delete posts. This project not only gives you a working example but also equips you with skills to tackle more advanced Laravel projects.

Remember, this is just the beginning. With Laravel, the possibilities are endless. As you gain more experience, you can expand your blog by adding features like authentication, file uploads, tags, and categories. Experience Laravel’s ecosystem, such as API routes and queues, to deepen your skills.

Happy coding, and may your Laravel journey be as smooth as the framework itself!

Related Posts

close-link
Register to ThemeSelection 🚀

Prefer to Login/Register with:

OR
Already Have Account?

By Signin or Signup to ThemeSelection.com using social accounts or login/register form, You are agreeing to our Terms & Conditions and Privacy Policy
close-link
Reset Your Password 🔐

Enter your username/email address, we will send you reset password link on it. 🔓

Privacy Preferences
When you visit our website, it may store information through your browser from specific services, usually in form of cookies. Here you can change your privacy preferences. Please note that blocking some types of cookies may impact your experience on our website and the services we offer.