Alternate template strategy - using a single output file

Posted 10th Sep 2017

#templatestrategy #templates

By default, processwire renders pages with a file located in '/templates/' which shares the same name as the template used to create the page.

For example, if the page has been created using a template called 'basic-page', then processwire looks for the file '/templates/basic-page.php' file to render the content. You can change this behaviour though by specifying that a template uses an alternate template instead.

This means you can put the skeleton of your entire website in one file i.e. main menu, header, footer, things that usually don't change much and are repeated across multiple pages, and then just render different body content for each page on your website. This file can be called whatever you like, I'm using '_main.php'.

/site/templates/_main.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 echo $page->title; ?></title>
</head>

<body class="<?php echo $page->template->name; ?>">
  <h1>I am in '_main.php' template</h1>
  <?php include("./{$page->template->name}" . ".php"); ?>
</body>

</html>

We use an underscore in '_main.php' so that processwire doesn't automatically detect this file when you go to 'Admin > Setup > Templates' and select 'Add New Template'.

This file is purely used to output the skeleton of the website and other templates and will not hold any data, therefore it can remain hidden from the system. You could refer to this as a parent or master template.

Admin > Setup > Templates > Files (tab)

Click on the template you want to assign an alternate template to, and on the template edit screen, select the files tab. Input '_main' into the alternate template filename field and save the template.

Changing alternate template filename field
Changing alternate template filename field Zoom

/site/templates/basic-page.php

<?php namespace ProcessWire; ?>

<h2>I am in 'basic-page.php' template file</h2>

<p><?php echo $page->title; ?></p>
<p>This page has been created using the '<?php echo $page->template->name; ?>' template</p>

Home (hover) > New

Create a new page using the 'basic-page' template. Fill in the title field with 'About me'. The 'name' field here can be customized to whatever you want but defaults to the hyphenated title. This is the URL where the page will be accessed. 'Save + Publish' the page, then select 'View'.

When viewed in the browser, the resulting page shows that the page using the basic-page template has been output through main.php.

Page created with the basic-page template and rendered through _main.php template file
Page created with the basic-page template and rendered through _main.php template file Zoom

Note that the title reflects the page title of the page you just created and the body class outputs the template used to create the page. Assigning an alternate template as '_main' can now be applied to all templates on your site that need to be rendered via a template file.

This approach is basically a dynamic include depending on what page you're on.

<?php
  // include a file which consists of the name of the template used to create the
  // current page with a .php extension appended onto it
  include("./{$page->template->name}" . ".php");

  // if on a page created with 'basic-page' template
  // include("basic-page.php");

  // if on a page created with 'contact' template
  // include("contact.php");

  // etc...
?>

With slight modification, you can easily move your templates into their own folder and include various other things that you might need. An example '_main.php' file might look something like this:

<?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 echo $page->title; ?></title>
</head>

<body class="<?php echo $page->template->name; ?>">

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

    include("./views/{$page->template->name}" . ".php");

    include("./includes/footer" . ".php");
  ?>

</body>

</html>

And then you can use a structure like this:

/templates/_main.php
/templates/views/basic-page.php
/templates/views/contact.php
/templates/views/about.php​​​​​​
/templates/includes/header.php
/templates/includes/footer.php

...rather than having every template in the '/templates/' directory.

The downside to this approach is that you have to remember to set '_main' as the alternate template each time you create a new template which will be used to render data. If you don't, then the system will do the default behaviour and look for 'TEMPLATE_NAME.php', which will give you a 404 not found.

Remember though that this is just one way of many.

You can check out the other strategies here.

Feedback & support

I hope you enjoyed this tutorial. You can support pwtuts by following on @pwtuts.

Related tutorials / See all