Creating a Blog Using Laravel 4 Part 4: Layout and Views

Previous parts of this tutorial:

This will be the last part of the Creating a Blog using Laravel series, In this part, we will cover the layout and views for the Blog Application we are creating. Let’s see what we have already covered:

  • Laravel Setup
  • Laravel Migrations
  • Model creation using Eloquent ORM
  • Database Seeding
  • Controllers
  • Routing

View: The V in MVC

Views in a MVC web framework are used to isolate the presentation logic from the business, and the application logic. In a typical MVC web framework, whenever a request is received, the routing component parses the request and figures out the right controller action to handle the request. The controller action, then fetches the requested data from the model and passes it to the view. And finally, a response is returned containing the HTML markup generated by the view to present the data.

Now, let us consider the following example to elaborate the idea using Laravel:

<?php
//file: app/controllers/IndexController.php

class IndexController extends BaseController {

    public function index()
    {
        return View::make('index',['name'=>'usman']);
    }
}

//file: app/routes.php

Route::get('index','IndexController@index');

//file: app/views/index.blade.php
<html>
<head>
    <title>Index page</title>
</head>
<body>
    <p> my name is {{$name}}</p>
</body>
</html>

In the above code, the file IndexController.php contains a simple controller class with an index action. In routes.php, we have registered a route to this action using Route::get(). Inside index() action, we are simply generating a view based on index.blade.php with a variable name. This variable is then presented inside index.blade.php using a p tag.

The Master Layout

The master layout is used to define a uniform look and feel of a web application, and usually contains the elements that are common to all the views. For example: header, footer and sidebars etc. Laravel has two options for creating the master layouts:

  • Controller layouts
  • Blade Template inheritance

Since, our controllers have already been set up to use controller layouts, covering the second option here is beyond the scope of this article.

Let us see the markup for the master layout (app/views/master.blade.php):

<!DOCTYPE html>
<html class="no-js" lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    @section('title')
        <title>{{{$title}}}</title>
    @show
    {{ HTML::style('assets/css/foundation.css') }}
    {{ HTML::style('assets/css/custom.css') }}
    {{ HTML::script('./assets/js/vendor/custom.modernizr.js') }}
</head>
<body>
<div class="row main">
    <div class="small-12 large-12 column" id="masthead">
        <header>
            <nav class="top-bar" data-topbar>
                <ul class="title-area">
                    <!-- Title Area -->
                    <li class="name"></li>
                    <!-- Remove the class "menu-icon" to get rid of menu icon. Take out "Menu" to just have icon alone -->
                    <li class="toggle-topbar menu-icon"><a href="#"><span>Menu</span></a></li>
                </ul>
                <section class="top-bar-section">
                    <ul class="left">
                        <li class="{{(strcmp(URL::full(), URL::to('/')) == 0) ? 'active' : ''}}"><a href="{{URL::to('/')}}">Home</a></li>
                    </ul>
                    <ul class="right">
                        @if(Auth::check())
                            <li class="{{ (strpos(URL::current(), URL::to('admin/dash-board'))!== false) ? 'active' : '' }}">
                                {{HTML::link('admin/dash-board','Dashboard')}}
                            </li>
                            <li class="{{ (strpos(URL::current(), URL::to('logout'))!== false) ? 'active' : '' }}" >
                                {{HTML::link('logout','Logout')}}
                            </li>
                        @else
                            <li class="{{ (strpos(URL::current(), URL::to('login'))!== false) ? 'active' : '' }}">
                                {{HTML::link('login','Login')}}
                            </li>
                        @endif
                    </ul>
                </section>
            </nav>
            <div class="sub-header">
                <hgroup>
                    <h1>{{HTML::link('/','Laravel 4 Blog')}}</h1>
                    <h2>Laravel 4 Simple Blog tutorial</h2>
                </hgroup>
            </div>
        </header>
    </div>
    <div class="row">
        {{$main}}
    </div>
    <div class="row">
        <div class="small-12 large-12 column">
            <footer class="site-footer"></footer>
        </div>
    </div>
</div>
{{ HTML::script('./assets/js/vendor/jquery.js') }}
{{ HTML::script('./assets/js/foundation.min.js') }}
<script>
    $(document).foundation();
</script>
</body>
</html>

NOTE 1:
To use the master layout across all the controllers, we need to define the protected $layout='master'; property in the BaseController, so that all the controllers inherit layout property.

NOTE 2:
I have used the Foundation 5 framework for the styling purpose, you can read my previous article on Foundation 5 to understand the markup and CSS classes I have used in the views.

In the head section of the master layout, I have linked the style sheets using HTML::style() method which generates a link tag with the href attribute set to the path provided as an argument. Similarly, HTML::script() is used to generate the links to the required JavaScript files.

Quick Tips:

  • In Laravel we use Blade Template Engine to write views.
  • To use Blade Template Engine, we save files with a blade.php extension.
  • In a view we can output content using {{ $title }}, this is Blade’s equivalent to <?php echo $title; ?>.
  • We can use control structures by using @if() @endif, @foreach @endforeach etc.
  • We can escape HTML by using triple curly brace syntax like: {{{ $title }}}.
  • See Blade’s Documentation for further details.

In the header section, the navigation for the blog is defined and some conditional expressions are used to display the active links. The dashboard and logout links will be displayed only if a user is logged in. {{$main}} is the pluggable section of the master layout which is used in controllers to insert child views.

A snippet from the getIndex action of the BlogController:

 <?php

//used to set the title variable in master layout.
$this->layout->title = 'Home Page | Laravel 4 Blog'; 

//used to insert partial view named as home.blade.php in the master layout.
//by using nest() we are injecting index view in the home view, exciting huh?
$this->layout->main = View::make('home')->nest('content','index',compact('posts'));

Creating Views

The app/views directory is used to hold the view files for an application. Here is a screenshot of our application’s views directory:

Creating a Blog Using Laravel 4 Part 4 Layout and Views
Views Directory Screenshot

Home, index and sidebar

home.blade.php

{{-- home page --}}
<div class="small-8 large-8 column">
  <div class="content">
    {{$content}}
  </div>
</div>
<div class="small-4 large-4 column">
  <aside class="sidebar">
    @include('sidebar')
  </aside>
</div>

index.blade.php

@if(!empty($notFound))
<p>Sorry nothing found for your query!</p>
@else
@foreach($posts as $post)
    <article class="post">
        <header class="post-header">
            <h1 class="post-title">
                {{link_to_route('post.show',$post->title,$post->id)}}
            </h1>
            <div class="clearfix">
                <span class="left date">{{explode(' ',$post->created_at)[0]}}</span>
                <span class="right label">{{$post->comment_count}} comments </span>
            </div>
        </header>
        <div class="post-content">
            <p>{{$post->read_more.' ...'}}</p>
            <span>{{link_to_route('post.show','Read full article',$post->id)}}
        </div>
        <footer class="post-footer">
            <hr>
        </footer>
    </article>
@endforeach
{{$posts->links()}}
@endif

sidebar.blade.php

{{ Form::open(['url' => 'search','method'=>'get']) }}
    <div class="row">
        <div class="small-8 large-8 column">
            {{ Form::text('s',Input::old('username'),['placeholder'=>'Search blog...']) }}
        </div>
            {{ Form::submit('Search',['class'=>'button tiny radius']) }}
    </div>
{{ Form::close() }}
<div>
    <h3>Recent Posts</h3>
    <ul>
    @foreach($recentPosts as $post)
        <li>{{link_to_route('post.show',$post->title,$post->id)}}</li>
    @endforeach
    </ul>
</div>

The home page contains two div elements: one to show the index content and the other is used to include the sidebar partial view using Blade’s @include directive.

In the index.blade.php, we are iterating through all the posts to show an index of published posts along with the Read More links.

Creating a Blog Using Laravel 4 Part 4 Layout and Views
Index Page Screenshot

View Composers
View Composers in Laravel, are callbacks that help us in defining the view logic. We can register a callback by using View::composer(). Whenever a view is rendered for which a callback is registered, Laravel will execute the callback before rendering the view.

You would have noticed that, we did not pass the $recentPosts variable to the sidebar partial in any controller action. This variable is actually populated by using the View Composer callback:

<?php
 View::composer('sidebar', function($view)
{
    $view->recentPosts = Post::orderBy('id','desc')->take(5)->get();
});

Dashboard, post listings and comment listings

dash.blade.php

<div class="small-3 large-3 column">
    <aside class="sidebar">
        <h3>Menu</h3>
        <ul class="side-nav">
            <li>{{HTML::link('/','Home')}}</li>
            <li class="divider"></li>
            <li class="{{ (strpos(URL::current(),route('post.new'))!== false) ? 'active' : '' }}">
                {{HTML::linkRoute('post.new','New Post')}}
            </li >
            <li class="{{ (strpos(URL::current(),route('post.list'))!== false) ? 'active' : '' }}">
                {{HTML::linkRoute('post.list','List Posts')}}
            </li>
            <li class="divider"></li>
            <li class="{{ (strpos(URL::current(),route('comment.list'))!== false) ? 'active' : '' }}">
                {{HTML::linkRoute('comment.list','List Comments')}}
            </li>
        </ul>
    </aside>
</div>
<div class="small-9 large-9 column">
    <div class="content">
        @if(Session::has('success'))
        <div data-alert class="alert-box round">
            {{Session::get('success')}}
            <a href="#" class="close">&times;</a>
        </div>
        @endif
        {{$content}}
    </div>
    <div id="comment-show" class="reveal-modal small" data-reveal>
        {{-- quick comment using ajax --}}
    </div>
</div>
Creating a Blog using Laravel 4 part 4 Layout and Views
Admin Dashboard Screenshot

In the admin dashboard, the links to the CRUD are shown in the left sidebar. The right pane is used to insert the partials for the CRUD operations: post listings, comment listings, new post etc.

The Reveal Modal plugin of Foundation 5 has a built-in support for Ajax, the last div element will be used by the Reveal Modal plugin to populate the Ajax content.

posts/list.blade.php

<h2 class="post-listings">Post listings</h2><hr>
<table>
    <thead>
    <tr>
        <th width="300">Post Title</th>
        <th width="120">Post Edit</th>
        <th width="120">Post Delete</th>
        <th width="120">Post View</th>
    </tr>
    </thead>
    <tbody>
        @foreach($posts as $post)
            <tr>
                <td>{{$post->title}}</td>
                <td>{{HTML::linkRoute('post.edit','Edit',$post->id)}}</td>
                <td>{{HTML::linkRoute('post.delete','Delete',$post->id)}}</td>
                <td>{{HTML::linkRoute('post.show','View',$post->id,['target'=>'_blank'])}}</td>
            </tr>
        @endforeach
    </tbody>
</table>
{{$posts->links()}}
Creating a Blog Using Laravel 4 Part 4 Layout and Views
Post Listing Screenshot

comments/list.blade.php

<h2 class="comment-listings">Comment listings</h2><hr>
<table>
    <thead>
    <tr>
        <th>Commenter</th>
        <th>Email</th>
        <th>At Post</th>
        <th>Approved</th>
        <th>Comment Delete</th>
        <th>Comment View</th>
    </tr>
    </thead>
    <tbody>
    @foreach($comments as $comment)
    <tr>
        <td>{{{$comment->commenter}}}</td>
        <td>{{{$comment->email}}}</td>
        <td>{{$comment->post->title}}</td>
        <td>
            {{Form::open(['route'=>['comment.update',$comment->id]])}}
            {{Form::select('status',['yes'=>'Yes','no'=>'No'],$comment->approved,['style'=>'margin-bottom:0','onchange'=>'submit()'])}}
            {{Form::close()}}
        </td>
        <td>{{HTML::linkRoute('comment.delete','Delete',$comment->id)}}</td>
        <td>{{HTML::linkRoute('comment.show','Quick View',$comment->id,['data-reveal-id'=>'comment-show','data-reveal-ajax'=>'true'])}}</td>
    </tr>
    @endforeach
    </tbody>
</table>
{{$comments->links()}}
Creating a Blog Using Laravel 4 part 4 Layout and Views
Comments Listings and Quick View using Ajax

Both the comments/list.blade.php and posts/list.blade.php share the same logic. In post/list.blade.php all the published posts are shown in a tabular form with links to certain admin CRUD operations like: edit, delete and view. The comments/list.blade.php has an additional form inside the td element. This form will be used for the comment moderation purpose.

The additional HTML attributes passed to the Quick View link are the requirements for the Reveal Model plugin to work properly.

Download Source Code

That’s all folks! I am skipping the rest of the views. You can download all the source code for the blog by using the above link and experiment as you like.

Thanks for reading this article and please write me your suggestions, or, if you have any questions, do not hesitate to ask!

26 thoughts on “Creating a Blog Using Laravel 4 Part 4: Layout and Views”

  1. Hey Usman,

    Great job with this tutorial! It’s tremendeously helpful, and seems very much up-to-date.

    Thanks a lot from a Laravel newbie 🙂

  2. I get this error though:

    ErrorException
    Creating default object from empty value

    When i’m trying to access any of the views that correspond to my PostController? Can you help? 🙂

    1. Make sure protected $layout='master' is set in your BaseController, provided that your master layout is named as master.blade.php.

    1. You can place the view composers inside your routes.php, global.php or create a custom composers.php file and include it inside one of the mentioned files. Thanks!

  3. I am getting a an error in chrome saying that the login page has a redirect loop anytime I try to load the login page. Everything looks in order to me. Any ideas?

    1. Make sure that the login route is not protected by the Auth filter. Check your before filters inside BlogController.

  4. sir i wanted to asking, how to access page with laravel routes
    and how to know available url i can open
    thanks
    i begining to learn laravel

    i open 127.0.0.1/laravel/public/

    it gives me :
    Whoops, looks like something went wrong.

    thank you

    1. You can use php artisan route command to see a dump of all the routes of your application.
      If your web server’s root is pointing to the Laravel’s public directory, you should be able to access Laravel by entering 127.0.0.1 in your browser’s address bar.
      “Whoops, looks like something went wrong” is a little ambiguous, you should turn on the error reporting by setting 'debug' => true in your app/config/app.php file to find out “what exactly went wrong”.

      1. Thanks Usman,
        i set it debug=>true
        and wow it’s worked, showing what’s wrong with it

        php artisan route also helpful

        now i begining to learning again,
        in your code i see Blueprint,
        what is’t for ?

        i tested this with laravel 4.1.28
        ended with login error
        it asking for remember_token
        i post it on your github,
        how to use this remember me, i cant find good enough in laravel doc
        Thanks a lot

        1. Thanks for the fixes regarding Laravel 4.1.26+, I have merged the changes. For the Blueprint see the Laravel Documentation Page on ‘Schema Builder’.
          You can utilize the remember me functionality by passing a true value as second argument to your Auth::atempt() call. Then, Auth::viaRemember() can be used to see if a user was authenticated with a remember me cookie. Hope it helps!

  5. I am getting an error in BlogContoller. Inside the function getIndex the following line :
    $posts->getEnvironment()->setViewName(‘pagination::simple’);

    call_user_func_array() expects parameter 1 to be a valid callback, class ‘Illuminate\Support\Collection’ does not have a method ‘getEnvironment’

    1. Hi, since the latest release of Laravel i.e, version 4.2, the Environment class has been renamed to Factory. I think using the method name getFactory instead of getEnvironment will fix the issue.

  6. Thank you for the response. I change the function name and not the page comes up but it is blank. Any other ideas of what I need to change?

    1. I have just installed a copy of Laravel 4.2 and it works fine with the changes I mentioned in my previous reply. Please checkout a copy of tutorial’s source code from git repository and see if problem still persists. Thanks!

    1. When using Controller Layouts I usually prefer to use the {{$main}} syntax. It is a matter of preference, use whichever you like.
      Thanks and Best Regards!

  7. Yeah,this tutorial is very perfect.Although i’m a foreigner,i can understand well.You know some countries have few tutorials of laravel,Thank goodness I found this tutorial, thanks a lot

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.