Laravel 5 Blog Tutorial

Download: Laravel Blog Tutorial Files

Introduction

Allow me to start this tutorial with a business perspective then jump into the technical aspect of it.

Why should you allow me to do this?

Because we develop technical tools that add value to the business of our clients. That is what clients pay us for. Successful web developers develop to add business value and not to show technical expertise when working with a particular technology. This can only happen if you understand the business value of whatever you are developing.

Almost any business that has an online presence needs to engage in content marketing. The contentmarketinginstitute.com defines content marketing as “Content marketing is a strategic marketing approach focused on creating and distributing valuable, relevant, and consistent content to attract and retain a clearly-defined audience — and, ultimately, to drive profitable customer action.”

Let me explain this in a layman’s language, let’s say you developed Larashop to sell dresses online.

How do you stand out and beat your competitors? What strategies can you use to rank in search engine results?

You need to establish yourself as an expert in the fashion industry. You can write content that advises women what to wear on a first date and then recommend your dresses to them. This increases the chances of them buying from you. To the owner of Larashop, this is business value.

How do you go about implementing this for Larashop?

You can use a blog to publish valuable, relevant, and consistent content.

Blogs can also be used to publish video, audio, pictures, or written content etc.

Laravel Blog

Topics to be covered

We will cover the following topics in this tutorial

  • Tutorial Pre-requisites
  • Features of a success blog
    • Post
    • Categories
    • Tags
    • Related Posts
    • Comments
    • User experience
    • Newsletter
  • Technical SEO factors
    • Post Title
    • Meta Description
    • Role of Social Media
  • Larashop Blog Database Migrations
  • Tutorial Project Larashop Blog Implementation

Tutorial pre-requisites

This tutorial assumes;

  • You understand the basics of Laravel
  • You have PHP, MySQL and Apache up and running
  • You have composer installed
  • You have a text editor or IDE that supports PHP.
  • You have a modern web browser that supports HTML5
  • You have been following the tutorial series for Larashop. You can still create a new Laravel project and follow the tutorial but you will gain more if you do other tutorials in the series first.

Features of a successful blog

Let’s now discuss the features that we will implement for Larashop blog

Post

This is the main content of the blog. The information that will be published. The information will be retrieved from the database and it will be formatted using HTML tags.

Categories

Categories are used to group related posts together. For example, you can have a category dedicated to women’s wear, another for men and another for kids.

Tags

Tags are similar to categories but they are more specialized. You can create tags for things like dating and tag all properties that related to dating regardless of the category. Users can browse by category and get all the items that match the specified tag i.e. dating

Related Posts

Related posts are used to show posts that are similar to the one that the reader is reading. Related posts can be displayed based on the category or post tags.

Comments

Comments allow you to get feedback from the readers. Comments are usually displayed at the end of the post. You can have a custom comment system or you can choose a third party system such as Disqus.

User experience

The user experience considers factors such as responsiveness of the design. Can the blog properly display on a mobile device? Is it easy to navigate the contents of the blog? How fast is the blog load time etc.?

Newsletter

In content marketing, customer retention of the major factors. Most blogs will have newsletter subscriptions that allow readers to subscribe. The subscription email address is used to send updates to subscribers whenever new content is published. You can either implement a custom newsletter or you can use a third party such as Mail chimp. The popular choice is using third parties. Third parties have a high delivery rate compared to custom ones.

Technical SEO factors

We do not want our blog to be number 1,678,901 in search results. We should aim for the first page, anything beyond the fourth page is bad for you.

Read the tutorial Laravel SEO Friendly URLs to understand how you can implement technical tools that help with search engine optimization.

Our blog implementation must provide the following database fields / features

  • Post Title – This should be limited to about 56 characters. It is the title that will be displayed in search results.
  • Meta Description – This should be limited to about 160 characters. It is the description that is displayed in search results.
  • Role of Social Media – Social media metrics are used to determine the value of content in search engine algorithms. The more social shares a post gets the better it will be ranked. You need to make it easier for visitors to share your content.

Larashop Blog Database Migrations

Now that we have complete Blog Basics 101, let’s get our hands dirty. The following tables show the database tables that we will need to create for our blog

Common Fields to all Tables

S/N FIELD DATA TYPE DESCRIPTION
1 created_at Timestamp Timestamp when record was created
2 updated_at Timestamp Timestamp when record was last updated

Blog_Categories Table

S/N FIELD DATA TYPE DESCRIPTION
1 id INT Primary key
2 category VARCHAR Category Name

Blog_Tags Table

S/N FIELD DATA TYPE DESCRIPTION
1 id INT Primary key
2 tag VARCHAR Tag Name

Blog_post_tags

S/N FIELD DATA TYPE DESCRIPTION
1 id INT Primary key
2 post_id INT Foreign key
3 tag_id INT Foreign key

Posts Table

S/N FIELD DATA TYPE DESCRIPTION
1 id INT Primary key
2 url Varchar(255) Page URL
3 title Varchar(140) Page title
4 description Varchar(170) Description that shows in search engine results
5 content Text The content of the page or blog post.
6 blog Tinyint(1) Determines if a post is a page is blog
7 category_id INT Foreign key
8 image Varchar(255) Blog post image

The migration file for posts table was created in the tutorial Laravel Migrations but we did not include the categoryid and post image. If you do not have the migration file for posts then read the tutorial Laravel Migrations. In this tutorial, we will create a migration file that adds the columns categoryid and image.

I have XAMPP installed on windows on drive C and Larashop is in larashop directory

Open the command prompt / terminal

Run the following command to browse to the project root.

cd "C:\xampp\htdocs\larashop"

Let’s now use artisan to create two migration files

Run the following commands

php artisan make:migration add_category_id_image_to_posts --table=posts

Open the newly created migration file /database/migrations/xxxx_xx_xx_xxxxxx_ add_category_id_image_to_posts.php

Modify the code to the following

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddCategoryIdImageToPosts extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->string('image')->nullable()->after('content');            
            $table->unsignedInteger('category_id')->nullable()->after('blog');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->dropColumn('image');
            $table->dropColumn('category_id');
        });
    }
}

HERE,

  • $table->string('image')->nullable()->after('content'); adds a string field image after the column content. The new column can accept null values.
  • $table->unsignedInteger('category_id')->nullable()->after('blog'); adds an unsigned integer category_id after the column blog. The new column can accept null values.

Run the following command to execute the migration

php artisan migrate

Let’s now create the migration file for blog_categories. Our migration file will also seed records to the new database table.

Run the following artisan command

php artisan make:migration blog_categories

Modify the code to the following

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class BlogCategories extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('blog_categories', function (Blueprint $table) {
            $table->increments('id');
            $table->string('category')->unique();
            $table->timestamps();
        });

        DB::table('blog_categories')->insert([
            'category' => "WOMEN"
        ]);

        DB::table('blog_categories')->insert([
            'category' => "MEN"
        ]);

        DB::table('blog_categories')->insert([
            'category' => "KIDS"
        ]);
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('blog_categories');
    }
}

Let’s now create the migration file for tags table

Run the following artisan command

php artisan make:migration blog_tags

Modify the code to the following

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class BlogTags extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('blog_tags', function (Blueprint $table) {
            $table->increments('id');
            $table->string('tag')->unique();
            $table->timestamps();
        });

        DB::table('blog_tags')->insert([
            'tag' => "Pink"
            ]);

        DB::table('blog_tags')->insert([
            'tag' => "T-Shirt"
            ]);
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('blog_tags');
    }
}

Let’s now create the migration file for blog_post_tags table

Run the following artisan command

php artisan make:migration blog_post_tags

Modify the code to the following

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class BlogPostTags extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('blog_post_tags', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('post_id');
            $table->unsignedInteger('tag_id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('blog_post_tags');
    }
}

Let’s now run our database migrations

php artisan migrate

Larashop Blog Dummy Records

We will use faker library to add dummy blog posts to our database. If you are not familiar with Faker library then I recommend you read this tutorial.

Run the following command to create a blog posts seed file

php artisan make:seeder BlogPostsTableSeeder

Open /database/seeds/BlogPostsTableSeeder.php

Update the code to the following

<?php

use Illuminate\Database\Seeder;

class BlogPostsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $faker = Faker\Factory::create();

        for ($i = 0; $i < 10; $i++){
            DB::table('posts')->insert([ //,
                'url' => $faker->unique()->word,
                'title' => $faker->unique()->sentence($nbWords = 6),
                'description' => $faker->paragraph($nbSentences = 3),
                'content' => $faker->text,
                'image' => $faker->randomElement($array = array ('blog-one.jpg','blog-two.jpg','blog-three.jpg')),
                'blog' => '1',
                'category_id' => $faker->numberBetween($min = 1, $max = 3),
            ]);
        }
    }
}

HERE,

  • 'url' => $faker->unique()->word, generates a unique random word to be used as the post URL. using words will boost our search engine optimization efforts compared to using a post id such as 2.
  • 'image' => $faker->randomElement($array = array ('blog-one.jpg','blog-two.jpg','blog-three.jpg')), we are picking a random image from the provided options. We only have three images for now that we will use for testing purposes.
  • 'category_id' => $faker->numberBetween($min = 1, $max = 3), we only created three categories so we will restrict the category id to numbers 1,2 and 3.
  • 'created_at' => $faker->dateTime($max = 'now'), created_at field will be used to display the blog post date.

Run the following artisan command to run the seed file.

php artisan db:seed --class=BlogPostsTableSeeder

Let’s now seed the blog post tags. blog_post_tags is used to link blog posts to tags

Run the following command to create the seed file

php artisan make:seeder BlogPostTagsTableSeeder

Open /database/seeds/BlogPostTagsTableSeeder.php

Modify the code to the following

<?php

use Illuminate\Database\Seeder;

class BlogPostTagsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $faker = Faker\Factory::create();

        for ($i = 1; $i < 11; $i++){
            DB::table('blog_post_tags')->insert([ //,
                'post_id' => $i,
                'tag_id' => $faker->numberBetween($min = 1, $max = 2),
            ]);
        }
    }
}

HERE,

  • 'post_id' => $i, we seeded only 10 records and our loop will be executed 10 times. We will use the loop counter variable for the post id.
  • 'tag_id' => $faker->numberBetween($min = 1, $max = 2), we only seeded two tags. This line generates a random number between 1 and 2 to match the tag ids that we have in our database.

Run the following artisan command to run the seed file

php artisan db:seed --class=BlogPostTagsTableSeeder

Blog Models

Let’s now create models for our blog. We will create the following models;

  • Post – this model will be responsible for interacting with the posts table
  • BlogCategory – this model will be responsible for interacting with the blog_categories table.
  • BlogTag – this model will be responsible for interacting with the blog_tags table.
  • BlogPostTag – this model will be responsible for interacting with the blog_post_tags table

Run the following artisan commands to create the above models

php artisan make:model Post
php artisan make:model BlogCategory
php artisan make:model BlogTag
php artisan make:model BlogPostTag

Update the model code as follows

Blog Post Model

Our blog posts will have URL for the previous and next posts. We will use the post id to determine the previous and next post. Towards that end, we will create two functions prevBlogPostURL and nextBlogPostURL.

We will use Eloquent ORM’s where clause and first function to get the previous and next URLs. The where clause for previous URL will use less than comparison operator and order the results in descending order. The where clause for next UR: will use greater than comparison operator and order the results on ascending order.

Blog post tags

The relationship between the blog post and the blog tags is many to many. A single post can have more than tag and a single tag can belong to more than one post. This relationship is implemented by introducing an intermediate table that links posts and blog_tags tables.

We will use Eloquent ORM’s belongsToMany function to define the relationship in Post model.

Open /app/Post.php

Modify the code to the following.

<?php

namespace App;

class Post extends BaseModel {

    protected $fillable = array('url', 'title', 'description', 'content', 'image', 'blog', 'category_id');

    public static function prevBlogPostUrl($id) {
        $blog = static::where('id', '<', $id)->orderBy('id', 'desc')->first();

        return $blog ? $blog->url : '#';
    }

    public static function nextBlogPostUrl($id) {
        $blog = static::where('id', '>', $id)->orderBy('id', 'asc')->first();

        return $blog ? $blog->url : '#';
    }

    public function tags() {
        return $this->belongsToMany('App\BlogTag','blog_post_tags','post_id','tag_id');
    }
}

HERE,

  • $blog = static::where('id', '<', $id)->orderBy('id', 'desc')->first(); builds the SQL statement similar to SELECT * FROM posts where id < 3 order by id limit 1 ; we are ordering the result using the id in an descending order so that we can get the lowest number just after 3. This will give us a single record with the id 2.
  • $this->belongsToMany('App\BlogTag','blog_post_tags','post_id','tag_id'); defines a many to many relationship between posts and blog_tags using the intermediate table blog_post_tags.

Blog Category Model

For now, this model does not need any special business logic.

Open /app/BlogCategory.php

Modify the code to the following

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class BlogCategory extends Model
{
    protected $fillable = array('category');
}

Blog Tag Model

This model has a many to many relationship with Post model. We will add a function posts that defines the relationship between the two tables.

Open /app/BlogTag.php

Modify the code to the following

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class BlogTag extends Model {

    protected $fillable = array('tag');

    public function posts() {
        return $this->belongsToMany('App\Post','blog_post_tags','post_id','tag_id');
    }
}

Blog Post Tag Model

This is the model for the intermediate table blog_post_tags. It does not contain any special logic for now.

Open /app/BlogPostTag.php

Modify the code to the following

<?php

namespace App;

class BlogPostTag extends BaseModel {
    protected $fillable = array('post_id', 'tag_id');
}

Blog Controller functions

For the sake of simplicity, we are working with a single controller /app/Http/Controllers/Front.php and it has two functions for our blog namely blog and blog_post.

Add the following line to import the Post model

use App\Post;

Blog controller function

This function is used to display the blog page and list all the postings that we have. Let’s say the client asks us to display only 3 posts per page. We can use pagination to limit the posts that we display. Eloquent ORM supports pagination.

Update the code for the function blog to the following

public function blog() {
    $posts = Post::where('id', '>', 0)->paginate(3);
    $posts->setPath('blog');

    $data['posts'] = $posts;

    return view('blog', array('data' => $data, 'title' => 'Latest Blog Posts', 'description' => '', 'page' => 'blog', 'brands' => $this->brands, 'categories' => $this->categories, 'products' => $this->products));
}

HERE,

  • $posts = Post::where('id', '>', 0)->paginate(3); paginates the returned results to three per page and assigns the result to the variable post.
  • $posts->setPath('blog'); sets the pagination URL to base URL + blog.
  • $data['posts'] = $posts; assigns the result to $data array variable.

Blog_post controller function

This function accepts a URL as a parameter and retrieves a single post based on the supplied URL value.

Modify the code to the following

public function blog_post($url) {
    $post = Post::whereUrl($url)->first();

    $tags = $post->tags;
    $prev_url = Post::prevBlogPostUrl($post->id);
    $next_url = Post::nextBlogPostUrl($post->id);
    $title = $post->title;
    $description = $post->description;
    $page = 'blog';
    $brands = $this->brands;
    $categories = $this->categories;
    $products = $this->products;

    $data = compact('prev_url', 'next_url', 'tags', 'post', 'title', 'description', 'page', 'brands', 'categories', 'products');

    return view('blog_post', $data);
}

The above code is self-explanatory if you have been following the tutorial series. Use the comments section to ask questions if you need any explanations.

Blog and Blog Post views

For the sake of brevity, we will not include the code for the views. Download the attached tutorial files to get the code for the views. The code is in /resources/views/blog.blade.php and /resources/views/blog_post.blade.php

Use the comments section to ask if you have any questions regarding the code in the views.

Summary

In this tutorial, we learnt how to create a blog using Laravel and the key features that should be implemented in order to create a successful blogging platform.

What’s next?

Our blog still needs a lot of work before we complete it. We haven’t yet implemented the comments section and the social media aspect of it. The next tutorial will focus on the custom comments section and integrating social media.

If you found this tutorial useful, support us by using the social media buttons to like and share the tutorial. If you didn’t find it useful, please use the comments section below to let us know how we can do better next time.

Each week, a new Laravel tutorial is added to our collection. Subscribe to our newsletter, like our Facebook fan page or follow us on Twitter to get free updates when the collection is updated.

Tutorial History

Tutorial version 1.1: Date Updated 2015-11-04 -Refactored the code for models [dropped DB class and implemented Eloquent ORM relationships], refactored blog and blog_post methods in Front controller to improve the code.

Tutorial version 1: Date Published 2015-11-04

Related Tutorials