laravel blade, how to append to a section

49,523

Solution 1

The example in the documentation from Laravel website does indeed seem to be flawed, but I think it's a markdown parsing problem on the website, the same docs on github show the correct code:

In any case @parent does indeed work. The example in the docs should look like this:

@extends('layouts.master')

@section('sidebar')
    @parent

    <p>This is appended to the master sidebar.</p>
@stop

@section('content')
    <p>This is my body content.</p>
@stop

A quick look in the Illuminate/View/Factory.php confirms what @parent does:

/**
 * Append content to a given section.
 *
 * @param  string  $section
 * @param  string  $content
 * @return void
 */
protected function extendSection($section, $content)
{
    if (isset($this->sections[$section]))
    {
        $content = str_replace('@parent', $content, $this->sections[$section]);
    }

    $this->sections[$section] = $content;
}

Solution 2

You can simply use @append...

@extends('layouts.master')

@section('sidebar')
    <p>This is appended to the master sidebar.</p>
@append

@section('content')
    <p>This is my body content.</p>
@stop

See here.

To understand how this works...

The compileStatements() method in the BladeCompiler calls the method compileAppend(), as you can see here:

/**
 * Compile Blade Statements that start with "@"
 *
 * @param  string  $value
 * @return mixed
 */
protected function compileStatements($value)
{
    $callback = function($match)
    {
        if (method_exists($this, $method = 'compile'.ucfirst($match[1])))
        {
            $match[0] = $this->$method(array_get($match, 3));
        }

        return isset($match[3]) ? $match[0] : $match[0].$match[2];
    };

    return preg_replace_callback('/\B@(\w+)([ \t]*)(\( ( (?>[^()]+) | (?3) )* \))?/x', $callback, $value);
}

In turn, that inserts a call to appendSection() which looks like this:

/**
 * Stop injecting content into a section and append it.
 *
 * @return string
 */
public function appendSection()
{
    $last = array_pop($this->sectionStack);

    if (isset($this->sections[$last]))
    {
        $this->sections[$last] .= ob_get_clean();
    }
    else
    {
        $this->sections[$last] = ob_get_clean();
    }

    return $last;
}

Solution 3

as mentioned before, I used @parent and it works fine for me. May be an example for extended title will helps:

master.blade.php

@section('title')
My Blog 
@stop
<!doctype html>
<html>
<head>
    @include('includes.head')
</head>
<body>
<div class="container-fluid">
    <div id="main" class="row">
            @yield('content')
    </div>
</div>
</body>
</html>

includes/head.blade.php

<meta charset="utf-8">
<title>@yield('title')</title>

post.blade.php

@extends('master')

@section('title')
@parent
| {{$post->title }}
@stop
@section('content')
// Post Body here ..
@stop

Therefore, The Title will be rendered to be like this:

My Blog | My Post Title


Actually, this will render something like:

<title>
    My Blog
    | My Post Title
</title> 

so you can use the section second parameter to set the values:

includes/head.blade.php

...
@section('title', 'My Blog')
...

post.blade.php

...
@section('title', '@parent | ' . $post->ar_name )
...

And this will render:

<title>My Blog | My Post Title</title> 

So you will get rid of the lines inside the title,

Hope that's helps.

Note: This is used for Laravel 5.2, Not quite sure but as I remember, it works for Laravel 4 too.

Share:
49,523
Amaynut
Author by

Amaynut

Updated on November 08, 2020

Comments

  • Amaynut
    Amaynut over 3 years

    If you look to laravel official documentation http://laravel.com/docs/4.2/templates It says that giving this layout:

    <!-- Stored in app/views/layouts/master.blade.php -->
    
    <html>
        <body>
            @section('sidebar')
                This is the master sidebar.
            @show
    
            <div class="container">
                @yield('content')
            </div>
        </body>
    </html>
    

    Extended by this view

    @extends('layouts.master')
    
    @section('sidebar')
    
    
        <p>This is appended to the master sidebar.</p>
    @stop
    
    @section('content')
        <p>This is my body content.</p>
    @stop
    

    Will append to the section sidebar. But actually if you try is it doesn't append, it just override the content from the extended template.

    I heard about others blade function like @append, @prepend, @parent... no one seems to work.

    Beside, this example in the official doc which doesn't work, I find that the blade documentation is very poor. There's nothing about blade function like @parent for instance.