Multiple layouts in Sage 9?

Hey everyone! I’ve building a couple of new projects using Trellis/Roots/Sage 9 and need to have different layouts for different parts of the site.

In general I probably need to make copies of app.blade.php and have some logic to switch between them?The documentation is still a bit sketchy and I think the example code for Sage 8 doesn’t apply here as we’re using blade now. Anyone who has this working and can offer some advice?

Thanks!
Kris

It is possible to select a template per page in WordPress, maybe this is the right approach?

1 Like

As @strarsis mentioned, you would leave app.blade.php and create your own new templates (views). Take a look in recourses/views and you should see template-custom.blade.php which you can copy and use as an example to work over. You can then select that template for a given page.

1 Like

I think you’re kind of looking at it backwards? app.blade.php is just extended by other templates. I.e. if you look at views/index.blade.php you’ll see:

@extends('layouts.app') // <-- this part here

@section('content')
  @include('partials.page-header')
...

If you want to use a different layout, all you need to do is create that layout in views/layouts and then @extend it in the template you want to use.

So, let’s say you had a post type called “Book” and you wanted Books to use a special layout. You might do something like this:

// views/layouts/book.blade.php
<!doctype html>
<html @php(language_attributes())>
  @include('partials.head')
  <body @php(body_class())>
    @php(do_action('get_header'))
    <div class="wrap container" role="document">
      <main class="main">
          @yield('content')
      </main>
    </div>
    @php(do_action('get_footer'))
    @php(wp_footer())
  </body>
</html>
//views/single-book.blade.php
@extends('layouts.book') // <-- the important part!

@section('content')
  @while(have_posts()) @php(the_post())
    {!! $book_content !!}
  @endwhile
@endsection

WordPress will use the template heirarchy to load views/single-book.blade.php when you’re viewing a single Book, and then Blade will use the @extends directive to load views/layouts/book.blade.php as the layout. There’s no need for any additional logic.

2 Likes

@alwaysblank:
So single-book.blade.php is a template for a single post?
And book.blade.php is a template for the archive page?

1 Like

views/single-book.blade.php is the template WordPress will load for a single Book-type post, yes. But views/layouts/book.blade.php is a layout template, just like views/layouts/app.blade.phpnot a Book-type archive template. Unless another template @extends it, as demonstrated above, it won’t appear anywhere.

My example above wasn’t intended to be comprehensive, just to illustrate how Sage uses the Blades in views/layouts. If you wanted to create an archive for Books using what I have above, you’d need to create views/archive-book.php and put @extends('layouts.book') at the top of it.

You don’t actually have to use layouts for anything, though: They’re just a convenient way to wrap your templates with stuff that’s the same across your theme. There’s nothing to prevent you from making views/single-book.blade.php look like this, completely avoiding loading a layout:

// views/single-book.blade.php
<!doctype html>
<html @php(language_attributes())>
  @include('partials.head')
  <body @php(body_class())>
    @php(do_action('get_header'))
    <div class="wrap container" role="document">
      <main class="main">
          {!! $book_content !!}
      </main>
    </div>
    @php(do_action('get_footer'))
    @php(wp_footer())
  </body>
</html>
3 Likes

Thanks for the explanation! Roots/Sage looks so different I forgot the old WordPress logic still works!

First time using Sage 9 - equally confused. Where does template-custom.blade.php come in on the custom template side? I’ve duplicated it, named my new template template-plain.blade.php > changed the @includes to pull a couple different files. For some reason, what I’ve done works locally, but when uploaded to the beloved wpengine, the pages show up completely blank. I’ve dumped wpengine’s cache and can’t for the life of me figure out why both template-custom.blade.php and template-plain.blade.php won’t show any content on the remote server. Sorry for the revival, this post was helpful, but I think I’m still fuzzy on the understanding.

You may be running into an issue specific to WPEngine. There’s some discussion and possible solutions here: Sage 9 on WPEngine

The solution is perfect and works - to echo resolving this issue when trying to use a custom page template and host your Sage 9 theme on WP Engine:

in sage > config > view.php

change: 'compiled' => wp_upload_dir()['basedir'].'/cache',
to: 'compiled' => '/tmp/sage-cache',

And re-upload your view.php file.

Thank you @alwaysblank - you’ve saved me much pain and suffering.

Edit: clarification on the issue.

2 Likes

Hello,

Looked around but didn’t see a post specific to my question and this seems to be the most relevant one.

So what I am trying to achieve is to have full-width templates for all my pages apart from the blog page and any subsequent blog posts.

Looking at the templates I see that app.blade.php is being used for all pages/posts and it has

<div class="wrap container" role="document">

I want to replace that for ALL pages too:

<div class="container-fluid" role="document">

BUT then keep it the same i.e. <div class="wrap container" role="document"> for the blog page and any subsequent blog post pages.

Now I did create a template by duplicating app.blade.php to template-fullwidth.blade.php to be used for all pages that require full-width containers which I can then select in WordPress for pages that I create that require full width but I somehow feel that this isn’t the best or mostly importantly DRY method of achieving what I would like if I only want to remove that small amount of code.

Once thats done i would be implementing this for the actual blog page itself:

which looks spot on for what I need to show my initial blog page.

SO is there an easy way to replace <div class="wrap container" role="document"> to <div class="container-fluid" role="document"> for ALL pages except the blog page and posts? which will in turn only require me to make a cutom template for the blog page which the above link describes…

please keep in mind that I am new to blade/sage 9 and have only previously used the old roots theme and I have read up on blade and watched screencasts etc but cannot seem to figure this out.

Hope all that makes sense… trying not to repeat my self in code and keep everything as clean as possible…

You could most easily achieve this with Sass:

.wrap {
  @extend .container;

  .blog &,
  .post-single & {
    @extend .container-fluid;
  }
}

(Or something like that. That’s untested.)

Or with Controller by adding a variable of classes that you fill conditionally:

<div class="wrap {!! $containerclass !!}" role="document">

@MWDelaney thank you for your quick reply.

Seems like the controller method would be simpler? as I am trying to keep the css as lean as possible.

however can you please elaborate?

newbie @ both sage9/blade/controllers and no idea on how to implement that. I read up on: GitHub - soberwp/controller: Composer package to enable a controller when using Blade with Sage 9 and info on this post here:

https://discourse.roots.io/t/how-to-create-a-controller-file-for-a-custom-template-page-in-sage-9/11833/4

I tried but all i get is broken pages :worried:

Honestly, I’d just set the container class full width by default and fixed width for blog/single pages in css. Much simpler than setting up these named specific classes all the time. And one could argue these bootstrap class names go against the concept of separating style and content.

In app/controllers/app.php add the following function to the class:

    public function containerclasses() {
        return “container-fluid”;
    }

In app/controllers create blog.php and make its contents:

<?php

namespace App;
use Sober\Controller\Controller;

class Blog extends Controller
{
    public function containerclasses() {
        return “container”;
    }
}

That should get you started!

EDIT: note, I wrote this from memory on my phone and didn’t test it.

This isn’t a helpful response to the question that was asked.

Thanks guys.

i briefly caught the deleted post that @SRawhloe posted…

@MWDelaney thank you. playing with this now after going through some blade docs and watching a few other screencasts to get my head around it.

I could just easily accomplish what i want by duplicating app.blade.php and creating new templates but then i would be inundated with loads of templates. Your way looks promising and hopefully i will have luck with it :slight_smile:

You could also just move the container class deeper into the templates but that’s less DRY.

Thanks guys for your input. Much appreciated.

I have played around with this for a few days now and cannot get my head around it. The code works with no errors but the container class isn’t reflected as I wanted. Most definitely because I’m new to blade and probably didn’t add in additional stuff to control it all (and when I did I just got errors galore).

I just went ahead and created a full-width template instead which I now manually select in pages that require the full-width container. It’s less DRY but working!