Blade Templating Basics

Every view() call so far has pointed at a Blade template — Laravel's built-in templating engine. Blade files live in resources/views/ and use the .blade.php double extension. It gives you clean, readable syntax for echoing data, control structures (if/loops), and — as the next lesson covers — reusable layouts and components, while still allowing plain PHP whenever you genuinely need it.

1. How Blade Actually Works

A .blade.php file isn't executed directly — Blade compiles it down into plain, ordinary PHP the first time it's used, and caches that compiled version in storage/framework/views/. Every request after that reuses the cached compiled file (Blade automatically recompiles only when the source template changes), so there's no meaningful runtime overhead compared to writing raw PHP templates by hand.

2. Echoing Variables Safely

Data passed to a view (as covered in the previous lesson) is echoed using double curly braces:

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

Critically, {{ }} automatically runs the value through PHP's htmlspecialchars() equivalent before printing it. This means characters like < and > get escaped into harmless entities rather than being interpreted as real HTML — protecting your page from XSS (cross-site scripting) attacks in cases where a value might contain user-submitted content.

For the rare case where you genuinely need to output raw, unescaped HTML — say, content from a trusted rich-text editor that's meant to render its own markup — Blade offers the unescaped syntax instead:

{!! $article->body_html !!}
Warning: Only ever use {!! !!} for content you fully trust. Printing unescaped user-submitted input this way is a direct, well-known route to an XSS vulnerability — an attacker-supplied <script> tag would execute exactly as written.

3. Core Control-Structure Directives

Blade directives are prefixed with @ and compile down to the equivalent plain PHP control structure:

DirectiveEquivalent to
@if / @elseif / @else / @endifPHP's if / elseif / else
@foreach / @endforeachPHP's foreach, for iterating over an array or collection
@for / @endforPHP's classic counted for loop
@while / @endwhilePHP's while loop
@if ($article->is_published)
    <span>Published</span>
@else
    <span>Draft</span>
@endif

@foreach ($articles as $article)
    <li>{{ $article->title }}</li>
@endforeach

4. Dropping Into Raw PHP with @php

For the occasional case where a template genuinely needs a snippet of raw PHP that doesn't map cleanly to any directive, Blade provides @php / @endphp:

@php
    $discounted = $article->price * 0.9;
@endphp

<p>Sale price: {{ $discounted }}</p>

Use this sparingly — if a view starts needing more than a line or two of logic like this, that's usually a sign the calculation belongs in the controller (or a model/service) instead, keeping the view focused purely on presentation.

5. Comments

Blade has its own comment syntax, distinct from regular HTML comments:

{{-- this comment is completely stripped out and never reaches the browser --}}
<!-- this HTML comment IS sent to the browser and visible in "View Source" -->

The difference matters: a Blade comment is removed entirely during compilation, so it never appears in the page's HTML source at all — useful for internal notes you don't want exposed to site visitors.

6. The $loop Variable

Inside any @foreach, Blade automatically makes a $loop variable available, carrying useful information about the current iteration — no manual counter needed:

@foreach ($articles as $article)
    @if ($loop->first)
        <h2>Latest Articles</h2>
    @endif

    <div class="article-row">
        <span>#{{ $loop->index + 1 }}</span>
        <strong>{{ $article->title }}</strong>
    </div>

    @unless ($loop->last)
        <hr>
    @endunless
@endforeach

$loop->index is zero-based (0, 1, 2, ...), $loop->first is true only on the first iteration, and $loop->last is true only on the final one — each genuinely handy for things like showing a heading once, or skipping a separator after the last item. @unless here is simply the inverse of @if.

7. A Full Worked Example

Putting several of these together — a view that loops over articles, numbers them using $loop, and falls back to a friendly message when the list is empty:

{{-- resources/views/articles/index.blade.php --}}
<h1>All Articles</h1>

@if ($articles->count() === 0)
    <p>No articles yet — check back soon!</p>
@else
    <ol>
        @foreach ($articles as $article)
            <li>
                {{ $loop->iteration }}. {{ $article->title }}
                @if ($loop->first)
                    <span>(newest)</span>
                @endif
            </li>
        @endforeach
    </ol>
@endif

$loop->iteration is a one-based counterpart to $loop->index — handy exactly for display purposes like this, where numbering usually starts at 1, not 0.

Up next: Blade: Layouts & Components covers reusing markup across pages with @extends, @section, and Blade components, so you're not repeating the same header/footer HTML in every view.