Base wrapper with fullwidth elements and sidebar with DRY

Hi there,

I’m having difficulties modifying the base wrapper so I can have the following two (very common) layouts without losing the DRY principle:

1) Fullwidth element (created in custom template) with underneath the normal main content in a container.

              +----------------------------------------+
              |               header                   |
+-------------+----------------------------------------+------------+
|                                                                   |
|                                                                   |
|                                                                   |
|                         fullwidth content                         |
|                                                                   |
|                                                                   |
|                                                                   |
+-------------+----------------------------------------+------------+
              |                                        |
              |                                        |
              |                                        |
              |                                        |
              |               main content             |
              |                                        |
              |                                        |
              |                                        |
              |                                        |
              |                                        |
              +----------------------------------------+

2) Fullwidth element (created from custom template) with underneath the normal main content including the sidebar in a container.

              +----------------------------------------+
              |               header                   |
+-------------+----------------------------------------+------------+
|                                                                   |
|                                                                   |
|                                                                   |
|                                                                   |
|                         fullwidth content                         |
|                                                                   |
|                                                                   |
|                                                                   |
+-------------+--------------------------+-------------+------------+
              |                          |             |
              |                          |             |
              |       main content       |   sidebar   |
              |                          |             |
              |                          |             |
              |                          +-------------+
              |                          |
              |                          |
              |                          |
              +--------------------------+

I know I can make a separate base template for each custom template, but that doesn’t really make much sense to me. Let’s say I have 4 different templates which all have different fullwidth elements created by different template parts and I want to keep the possibility to enable or disable the sidebar for each template.

First I would have to make the 4 custom templates (without the fullwidth elements) in order to use the custom base wrappers per template in which I could call the fullwidth template parts without a container and before the main content.

Then you basically have 4 identical base wrappers with only one get_template_part different?

Another way would be to remove the container class from the wrap and the row class from the content and remove the sidebar altogether. But that would mean that you have to repeat the sidebar conditional in EVERY template:

<?php if (Config\display_sidebar()) : ?>
  <aside class="sidebar" role="complementary">
    <?php include Wrapper\sidebar_path(); ?>
  </aside>
<?php endif; ?>

Both methods don’t really follow the DRY principle…
Is there another smart way to achieve this which I’m overlooking?

Thanks!

I could be completely out of touch but can’t you just do this with CSS?

<div class="container">
  <div class="navbar navbar-default">
    <div class="navbar-header">
      <div class="navbar-brand">Roots</div>
    </div>
  </div>
  <div class="full-width">
    <div class="full-width-inner">I'm full width</div>
  </div>
  <div class="row">
    <div class="col-sm-6">
      <div class="main-content">Main content, yo</div>
    </div>
    <div class="col-sm-6">
      <div class="panel panel-default">
        <div class="panel-body">Sidebar stuff</div>
      </div>
    </div>
  </div>
</div>
.main-content {
  background: #f1f1f1;
}

$offset: calc(-1 * (100vw - 100%)/2);

.full-width {
  margin-left: $offset;
  margin-right: $offset;
  background: #bada55;
  &-inner {
    text-align: center;
    font-size: 2rem;
    width: 100%;
    border: 5px #1d1d1d solid;
    padding: 10%;
  }
}
2 Likes

Thanks for this, I suppose you could use CSS for this yes.
However this wouldn’t be completely cross-browser compatible with the 100vw usage.
I also get a horizontal scrollbar in your codepen when there’s a vertical scrollbar.

Surprisingly, vw is actually pretty well supported.

Your only other option is basically changing .container on the wrapper div to .container-fluid, and using a .container class in each section to contain the content.

I’m sure there are dozens of examples and ideas you could pull from the Live Examples thread if you want to see how others are doing it. But in reality, it’s just how you set up your CSS and Bootstrap classes, there’s nothing magical about it.

1 Like

Actually this won’t work when you have a sidebar, the offset won’t work then:

$offset: calc(-1 * (100vw - 100%)/2);

That won’t work either because the main and aside element should be in the same container?

Don’t get me wrong, I know how to achieve this (I’ve done this layout before), but that involved removing the .container and .row class entirely from the base.php and adding the sidebar conditional in every template manually, which is totally against the DRY principle.

The only other way I can think of is this markup in the base:

<div class="wrap" role="document">
  <?php get_template_part('templates/header', 'fullwidth-carousel'); ?>
  <div class="container">
    <div class="content row">
      <main class="main" role="main">
        <?php include Wrapper\template_path(); ?>
      </main><!-- /.main -->
      <?php if (Config\display_sidebar()) : ?>
        <aside class="sidebar" role="complementary">
          <?php include Wrapper\sidebar_path(); ?>
        </aside><!-- /.sidebar -->
      <?php endif; ?>
    </div><!-- /.content -->
  </div><!-- /.container -->
</div><!-- /.wrap -->

But the problem is, that this line:
get_template_part('templates/header', 'fullwidth-carousel');
Should be in my actual template file because the template part is different in every template…

I guess I should make different base- templates for every template then after all, I just thought there could be an easier way.

Thanks for your suggestions!

1 Like

Use your markup and pass a function as the second parameter of get_template_part and determine which template to use that way. That way you will have one base.php file and one logic file, which is about a DRY as it gets.

1 Like

I don’t know that these really solve the issue Twansparant, and myself are wondering about. The object with DRY is to not place the sidebar calls in the individual templates, but rather in the base.php file so we’re not typing “get_sidebar()” in every page template correct? This is fine when everything uses the same layout, but if we want a page with no sidebar, or a left sidebar, or 2 sidebars etc, then we’re required to create new base-*.php files and then shift their position in the $templates array based on “get_page_template()”, correct?

I’m very new to roots, so perhaps I’m misunderstanding something, but it seems as though this actually creates more work for even your average site that uses sidebars(or any of the elements that we’re not trying to repeatedly write calls for) in different places.

We could easily do something like hide the sidebar and force the main content full width with CSS based on page template, but I’m wondering if there’s a (good) way to not even call the sidebar without having to get into editing our extras.php file for every new page layout.

Of course. lib/config.php is where you control if the sidebar is displayed or not.

1 Like

The object of being DRY is to create a system where:

Every piece of knowledge must have a single, unambiguous, authoritative representation

By programmatically setting which pages should display the sidebar in lib/config.php we create that single, unambiguous and authoritative representation of which pages will not have the sidebar shown.

Of course you can override this with a plugin like mine if you want clients to have control if a sidebar is shown or not, but lib/config.php should still be the best way to do it for a dev.

Regarding complex layouts, you can either mimic the sidebar display logic to control the display of the various components independently; or you can create several base templates and override which base template should be used by filtering sage/wrap_base; or you can use a plugin like ACF and code the templates part to show data only if it exists.

2 Likes

Thanks a lot for the super fast responses guys - I probably could have spent a little more time researching, but I saw this post asking the exact question I was already thinking - makes total sense now.

Thanks foxaii, I’m gonna try that!

This works great actually!
I added the following function call in the get_template_part function:

In base.php:

get_template_part('templates/fullwidth', Sage\Extras\base_header_path());

In this function it checks if any of the ACF fields are present, and returns the correct fullwidth template part to the base:

In lib/extras.php:

/**
 * Determine which header element to use in base
 */
function base_header_path() {
  // Carousel
  if ( get_field('acf_carousel_images') ) {
    return 'image-carousel';
  // Header Collage  
  } elseif( get_field('acf_page_header_collage') ) {
    return 'image-collage';
  // Header Image  
  } elseif ( get_field('acf_page_header_image') ) {
    return 'image-header';
  // Nothing  
  } else {
    return null;
  }
}

Thanks for the tip!

5 Likes

Hi guys! I’m wondering how one would approach this using Sage 9? I’m new to Sage and I can’t see how this translates. Thanks