Building a website with bootstrap 4 - direct output template strategy

Posted 15th Oct 2017

#bootstrap4 #completeguide #templatestrategy

We want to prepend the header template before the page template loads, then append the footer template after the page template. This saves having to use a php include() for the header and footer on every page template. This can be set in your config.php file so add the following code to that file.

This only applies if you want the header and footer on every page of your website, which is usually the case. Otherwise, you can just include the templates whenever they are required inside the page template files i.e. by using:

<?php include("./includes/header.php"); ?>

/site/config.php

/**
 *
 * Prepend template file
 *
 */
$config->prependTemplateFile = "./includes/header.php";

/**
 *
 * Append template file
 *
 */
$config->appendTemplateFile = "./includes/footer.php";

/site/templates/basic-page.php

<?php namespace ProcessWire; ?>

<div class="container">
  <div class="row py-5 justify-content-center align-items-center">
  <?php
    // if the page has a featured image
    if ($page->featuredImage):
    // https://processwire.com/api/fieldtypes/images/
    // set some default image options
    $options = array('quality' => 80, 'cropping' => 'center');
    // create a new image on the fly 800px wide
    $img = $page->featuredImage->width(800, $options);
    // get the url to the image
    $imgUrl = $img->url;
    // get the description field
    $imgDesc = $img->description;
  ?>

    <div class="col-md-6">
      <img src="<?php echo $imgUrl; ?>" alt="<?php echo $imgDesc; ?>" class="img-fluid" />
    </div>

    <?php endif; ?>
  
    <?php
      // change class name if image is present
      if ($page->featuredImage) {
        $colClassName = "col-md-6";
      }
      else {
        $colClassName = "col";
      }       
    ?>
    <div class="<?php echo $colClassName; ?>">
      <h2><?php echo $page->summary; ?></h2>
    </div>

  </div>
</div>

/site/templates/home.php

<?php namespace ProcessWire; ?>

<div class="container py-5">
  <h2>Services</h2>

  <div class="row">

    <?php
      // get the child pages of the current page
      $servicesPages = $pages->find("template=services-entry, limit=3");
      foreach ($servicesPages as $servicesPage):
    ?>
  
    <div class="col-md-4">
      <div class="card">

        <?php
        // if the page object has a featured image
        if ($servicesPage->featuredImage):
        // https://processwire.com/api/fieldtypes/images/
        // set some default image options
        $options = array('quality' => 80, 'cropping' => 'center');
        // create a new image on the fly 800px wide
        $img = $servicesPage->featuredImage->width(400, $options);
        // get the url to the image
        $imgUrl = $img->url;
        // get the description field
        $imgDesc = $img->description;
        ?>

        <a href="<?php echo $servicesPage->url; ?>">
          <img src="<?php echo $imgUrl; ?>" alt="<?php echo $imgDesc; ?>" class="img-fluid card-img-top" />
        </a>

        <?php endif; ?>

        <div class="card-body">
          <h4 class="card-title">
            <a href="<?php echo $servicesPage->url; ?>"><?php echo $servicesPage->title; ?></a>
          </h4>
          
          <p class="card-text">
          <?php
            if ($servicesPage->summary) {
              echo $servicesPage->summary;
            }
          ?>
          </p>
        </div>

      </div>
    </div>

    <?php endforeach; ?>

  </div>
</div>


<div class="container pb-5">
  <div class="row justify-content-center align-items-center">
  <?php
    // https://processwire.com/api/fieldtypes/images/
    // set some default image options
    $options = array('quality' => 80, 'cropping' => 'center');
    // create a new image on the fly 800px wide
    $img = $page->featuredImage->width(800, $options);
    // get the url to the image
    $imgUrl = $img->url;
    // get the description field
    $imgDesc = $img->description;
  ?>

    <div class="col-md-6">
      <img src="<?php echo $imgUrl; ?>" alt="<?php echo $imgDesc; ?>" class="img-fluid" />
    </div>
  
    <div class="col-md-6">
      <h2><?php echo $page->summary; ?></h2>
    </div>

  </div>
</div>

/site/templates/services-entry.php

<?php namespace ProcessWire; ?>

<div class="container">
  <div class="row py-5">
    <div class="col-md-3">
      <h2>Services</h2>
      <ul class="list-unstyled">
          
        <?php
          // get the child pages of parent page
          $childPages = $page->parent->children;
          // iterate over them to create a menu
          foreach ($childPages as $childPage):
        ?>
        
        <li><a href="<?php echo $childPage->url; ?>"><?php echo $childPage->get("altTitle|title"); ?></a></li>
  
        <?php endforeach; ?>

      </ul>
    </div>

    <div class="col-md-9">

    <?php
      // if the page has a featured image
      if ($page->featuredImage):
      // https://processwire.com/api/fieldtypes/images/
      // set some default image options
      $options = array('quality' => 80, 'cropping' => 'center');
      // create a new image on the fly 800px x 400px
      $img = $page->featuredImage->size(800, 400, $options);
      // get the url to the image
      $imgUrl = $img->url;
      // get the description field
      $imgDesc = $img->description;
    ?>

      <img src="<?php echo $imgUrl; ?>" alt="<?php echo $imgDesc; ?>" class="img-fluid mb-3" />

    <?php endif; ?>
      
    <?php
      // check if body field exists
      if ($page->body) {
        echo $page->body;
      }
    ?>

    </div>
  </div>
</div>

/site/templates/views/services-index.php

<?php namespace ProcessWire; ?>

<div class="container">
  <div class="row py-5">
  <?php
    // get the child pages of the current page
    $childPages = $page->children;
    foreach ($childPages as $childPage):
  ?>
  
  <div class="col-md-4">

    <div class="card">

    <?php
      // if the page object has a featured image
      if ($childPage->featuredImage):
        // https://processwire.com/api/fieldtypes/images/
        // set some default image options
        $options = array('quality' => 80, 'cropping' => 'center');
        // create a new image on the fly 800px wide
        $img = $childPage->featuredImage->width(400, $options);
        // get the url to the image
        $imgUrl = $img->url;
        // get the description field
        $imgDesc = $img->description;
    ?>
      
      <a href="<?php echo $childPage->url; ?>">
        <img src="<?php echo $imgUrl; ?>" alt="<?php echo $imgDesc; ?>" class="img-fluid card-img-top" />
      </a>

    <?php endif; ?>
      
      <div class="card-body">
        <h4 class="card-title">
          <a href="<?php echo $childPage->url; ?>"><?php echo $childPage->title; ?></a>
        </h4>
        <p class="card-text">
          <?php
            if ($childPage->summary) {
              echo $childPage->summary;
            }
          ?>
        </p>
      </div>

    </div>
  </div>

  <?php endforeach; ?>

  </div>
</div>

/site/templates/styles/main.css

header {
  text-align: center;
}

footer {
  background-color: #444;
  color: #fff;
  text-align: center;
  font-size: 0.8rem;
}

/site/templates/includes/header.php

<?php namespace ProcessWire; ?>

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">

  <title>
    <?php
      // print the current page field altTitle value
      // if blank or not present, print title field value
      echo $page->get("altTitle|title");
    ?>
  </title>

  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
  <link rel="stylesheet" href="<?php echo $config->urls->templates; ?>styles/main.css">
</head>

<body>

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" href="/">Big Meow Services</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarNav">
    <ul class="navbar-nav">

    <?php
      // get the homepage object
      $homePage = $pages->get("/");
      // get PageArray of homepage object and child page objects
      $navItems = $homePage->and($homePage->children);
      // or if you don't want the home link
      // $navItems = $homePage->children;
      // iterate over the $navItems PageArray
      foreach ($navItems as $navItem):
    ?>

      <li class="nav-item">
        <a class="nav-link" href="<?php echo $navItem->url; ?>"><?php echo $navItem->title; ?></a>
      </li>

      <?php endforeach; ?>

    </ul>
  </div>
</nav>

<header>
  <div class="jumbotron jumbotron-fluid">
    <div class="container">

      <h1 class="display-3"><?php echo $page->title; ?></h1>
      <p class="lead">
      <?php
        // only print this if the summary field exists
        // on the current page
        if ($page->altTitle) {
          echo $page->altTitle;
        }
      ?>        
      </p>
      
    </div>
  </div>
</header>

/site/templates/includes/footer.php

<?php namespace ProcessWire; ?>

<footer class="py-5">
  <div class="container">
    <p class="mb-0">
      &copy; Copyright Big Meow Services - <?php echo $datetime->date($format = "Y"); ?>
    </p>
  </div>
</footer>

</body>

</html>

Feedback & support

I hope you enjoyed this tutorial. You can support pwtuts by following on @pwtuts. You can also donate at paypal.me/swcarrey to help support the site which would be awesome!

Related tutorials / See all

Suggest a tutorial

Please note: I do not store any of this information, it's simply used to send me an email. Your email address is required so I can get clarification on your request if needed.