37

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.

Amaynut
  • 4,091
  • 6
  • 39
  • 44
  • 1
    I agree with you that the Blade templating Engine lacks a lot from a maturity point of view, reflected by the very lacking documentation. I personally think its one of the (few) weak points of Laravel, which luckily you can avoid if you want to by plugging in another template engine such as Smarty. I decided to go with that approach (look here for my earlier question http://stackoverflow.com/questions/25900826/how-to-include-smarty-3-into-laravel-4?noredirect=1#comment40616359_25900826). Blade users seem to be quite satisfied with it though, so maybe someone will look into your issues too. – jbx Oct 28 '14 at 18:37
  • @jbx Use another template engine, I think it's good idea. I think the popular **Twig** from the symfony framework seems to be a good option for a laravel project, even if it's harder to learn. Twig is also better than blade because you can use it in almost any php project, not only tied to laravel. For smarty, I just find it's official http://www.smarty.net website horrible. – Amaynut Oct 28 '14 at 18:49
  • If you find a good Laravel provider for Twig then you can use it if you prefer. I just prefer Smarty because I have lots of experience with it and I prefer the syntax to Twig's (I hate the double curly `{{` and the inconsistency with `{%` etc), but its definitely more mature than Blade. I find Smarty's documentation very comprehensive (its a totally different league compared to Blade). All the functions are very well documented with a full explanation and example. Maybe the website is a bit old fashioned (I think its one of the oldest PHP template engines) but its got everything. – jbx Oct 28 '14 at 23:16

3 Answers3

65

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;
}
Muhammad Dyas Yaskur
  • 6,914
  • 10
  • 48
  • 73
Bogdan
  • 43,166
  • 12
  • 128
  • 129
  • 3
    That's why I said that the documentation is still poor for Laravel in general, not only for blade component. You find yourself diving into the source code to see how to use a function! Not everyone is willing to do that. Even the comments inside the source code are very terse. You have to be an expert in Laravel to understand them. – Amaynut Oct 28 '14 at 20:33
  • @Amaynut I think it's a matter of perspective. I agree there as some things lacking in places from the documentation, but I would not call it poor. Also diving into the source code is not that much of a pain, in fact I think it's a good thing, and every developer commited to learning a new tool should try to understand how it works as best as possible (nobody can expect to be an expert from the get-go, but someone with some coding experience should not find it daunting at all). – Bogdan Oct 28 '14 at 20:48
  • 1
    @Bogdan That's a very skewed point of view and not 'a good thing' at all. When you provide a framework you should never throw it there and expect people to read the code to be able to use it. It defeats the whole point of encapsulation, reuse and basic software engineering principles. Obviously this is open source and the fact that it is free with no strings attached reduces the level of commitment expected from the author (which if I am not mistaken is still one main guy at the moment). But this doesn't suddenly make it 'good', well documented APIs are still better than undocumented ones. – jbx Oct 28 '14 at 23:26
  • @jbx I think you misunderstood. I wasn't arguing that it's not important to have good documentation. I was just pointing out the magic of open source, if you want to understand the inner workings of something you can, and you can't say that that's _"not 'a good thing' at all"_. – Bogdan Oct 28 '14 at 23:43
  • 2
    @Bogdan, Yes yes of course, and in no way do I want to demean the work the guy does on Laravel. I think its awesome. However, I disagree with some people's view that you just throw something out there and expect people to make sense out of it. The code could be thousands of lines while a simple description of a few lines describing how a function behaves would suffice for users to get on with it. Apart from the fact that there could be a bug, and the mismatch between the intended documented behaviour and the actual implementation emerges, which enables people to identify it and fix it. – jbx Oct 29 '14 at 00:16
28

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;
}
user1960364
  • 1,951
  • 6
  • 28
  • 47
  • 1
    It doesn't work, the append will just overrite the parent section. Why you don't try you solution before posting? – Amaynut Nov 05 '14 at 19:41
  • 1
    It does work, and I am currently using it in several of my projects. It was added in Laravel 4.1 as Taylor says [here](https://github.com/laravel/framework/issues/2662#issuecomment-27937143) and still works in the dev branch of Laravel 5. It worked fine for the OP in [this thread](https://laracasts.com/discuss/channels/general-discussion/blade-question) too. – user1960364 Nov 06 '14 at 01:44
  • sorry, but I have the latest Lavarel stable release, 4.2, I tested but it doesn't work. Only the **@parent** method works for me. If ommit **@parent**, it just overrite no matter which method you use **@stop**, **@show**, **@endsection**, **@append**... even in the thread you refered to in your comment they mention this: "NVM, got it - needed the '@parent'" – Amaynut Nov 06 '14 at 15:15
  • If you look at the timestamps, that comment was made before my comment. He then marked mine as the answer. I can assure you it works and I did test it before posting it. – user1960364 Nov 07 '14 at 04:15
  • It works in 4.2 but there is a slight change. The first section should end with '@stop' or '@show' and the subsequent ones should end with '@append'. – Umair Ahmed Jun 16 '15 at 10:45
  • Worked for me in 5.2. This should be marked as solution. – gorodezkiy Apr 20 '16 at 11:53
  • Worked in 8 when I used the '@parent' way my content got ordered wrong '@append' did order it correctly seems like this should be the accepted answer – Nico Shultz Aug 04 '21 at 09:14
  • A note on a slightly confusing behavior that could cause arguments like above to stil come up. If you add a `@section` ending with `@append` it might still look like it's overwriting another section if that other section ends with `@endsection` instead of `@append`. Happened to me just now. You might think that the section ending with `@endsection` would be overwriting the other one in which case the error would be more obvious, but apparently it doesn't have to be like that (at least in Laravel 6). – Rafał G. Oct 08 '21 at 11:01
1

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.

MohannadNaj
  • 1,029
  • 13
  • 12