Blade Templates

Laravel Fundamentals
Course 1 ยท Chapter 4 ยท Blade Templates

๐Ÿ—ฒ Blade Templates

view() from the last chapter needs an actual template file. Blade is Laravel's templating engine โ€” same job as the Django Template Language, different punctuation: @if instead of {% if %}, and directives compiled straight down to plain PHP rather than DTL's intentionally restricted mini-language.

Where Blade Views Live

Every Blade file lives in resources/views/, with dot notation mapping to nested folders โ€” a flatter convention than Django's app-namespaced templates/appname/ directories:

resources/views/
โ”œโ”€โ”€ layouts/
โ”‚   โ””โ”€โ”€ app.blade.php
โ”œโ”€โ”€ books/
โ”‚   โ”œโ”€โ”€ index.blade.php
โ”‚   โ””โ”€โ”€ show.blade.php
// In a controller (Chapter 3):
return view('books.index', ['books' => Book::all()]);
// 'books.index' -> resources/views/books/index.blade.php

๐Ÿ”ค Variables & Echoing

{{ }} auto-escapes by default โ€” the same XSS defense Django's {{ }} provides, just with curly braces instead of DTL's own:

<h1>{{ $book->title }}</h1>

// If $book->title contains <script>, this renders as inert text,
// not an executable script tag โ€” identical protection to Django's auto-escaping.

{!! !!} is Blade's equivalent of Django's |safe filter โ€” it opts out of escaping entirely:

{!! $book->trusted_html_description !!}
// โš ๏ธ NEVER on unsanitized user input โ€” same warning as Django's |safe,
// direct callback to the XSS course

Control Structures

@if ($books->isEmpty())
  <p>No books yet.</p>
@else
  <ul>
  @foreach ($books as $book)
    <li>{{ $loop->iteration }}. {{ $book->title }}</li>
  @endforeach
  </ul>
@endif

$loop is Blade's automatic loop variable โ€” $loop->iteration, $loop->first, $loop->last โ€” the direct equivalent of Django's forloop.counter and friends, available inside any @foreach without being passed in from the controller.

Django Template Language vs Blade โ€” Same Job, Different Punctuation

Django Template Language
{% if books %}
  {% for book in books %}
    {{ book.title|upper }}
  {% endfor %}
{% else %}
  No books.
{% endif %}
Blade
@if($books->isNotEmpty())
  @foreach($books as $book)
    {{ strtoupper($book->title) }}
  @endforeach
@else
  No books.
@endif

๐Ÿงฉ Template Inheritance

Blade's version of extends/block uses @extends/@section/@yield instead:

A Layout and a Child View

<!-- resources/views/layouts/app.blade.php -->
<!DOCTYPE html>
<html>
<head>
  <title>@yield('title', 'My Library')</title>
</head>
<body>
  <nav>Home | Books</nav>
  @yield('content')
  <footer>&copy; 2026</footer>
</body>
</html>

<!-- resources/views/books/index.blade.php -->
@extends('layouts.app')

@section('title', 'All Books')

@section('content')
  <ul>
  @foreach ($books as $book)
    <li>{{ $book->title }}</li>
  @endforeach
  </ul>
@endsection

@yield vs @section/@endsection

The layout declares a placeholder with @yield; a child view fills it with @section/@endsection โ€” Django's {% block %} plays both roles in one tag, Blade splits it into two.

@include

Pulls in a reusable partial inline โ€” @include('books.book-card') โ€” the same job as Django's {% include %}.

A Real Philosophical Difference

Course 1's Django Templates chapter emphasized DTL's deliberate restriction โ€” no method calls with arguments, no arbitrary Python. Blade takes the opposite stance: it compiles directly to plain PHP, so @php blocks (and even calling PHP functions inline, as strtoupper($book->title) did above) are fully available:

@php
    $discountedPrice = $book->price * 0.9;
@endphp

<p>Sale price: {{ number_format($discountedPrice, 2) }}</p>

This is genuinely more powerful and genuinely easier to misuse โ€” DTL's restriction exists specifically to keep business logic out of templates; Blade trusts the developer to maintain that discipline manually.

๐Ÿ’ป Coding Challenges

Challenge 1: Render a List With Blade

Write a Blade view that loops over a $books variable, printing each title using $loop->iteration for numbering, with a fallback message if the collection is empty.

Goal: Practice @if/@foreach together with the $loop variable.

โ†’ Solution

Challenge 2: Build a Layout + Two Child Views

Write a layouts/app.blade.php with @yield('title') and @yield('content'), then two child views (books/index.blade.php and books/show.blade.php) that each @extends it with different content.

Goal: Practice the @extends/@section/@yield inheritance pattern across more than one page.

โ†’ Solution

Challenge 3: Demonstrate Escaping

Pass a string containing <script> tags into a Blade view, render it two ways โ€” once as {{ $value }} and once as {!! $value !!} โ€” and explain what each one actually sends to the browser.

Goal: Practice recognizing Blade's auto-escaping in action, the same way Django's Templates chapter did for DTL.

โ†’ Solution

โš ๏ธ Gotcha: {!! !!} on User Input

The exact same warning from Django's |safe filter applies here, just with Blade's syntax: {!! $comment->text !!} on anything that ultimately traces back to user input is a direct XSS vulnerability, since it disables the one built-in protection Blade provides by default. Reserve {!! !!} for content that's already been through a real sanitization step โ€” never as a quick fix for an escaping-related rendering issue.

๐ŸŽฏ What's Next

Views can now display data โ€” the next chapter covers where that data actually comes from: Eloquent ORM, defining models, migrations, and querying with Eloquent's query builder compared to Django's ORM.