Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

UncleCheese
2nd January 2015

Typically a site has more than one distinct template used across all pages. The home page, for instance, is likely to have a different layout than the “About Us” page or an image gallery.In this tutorial, we’ll introduce a custom template for the home page, and start cleaning up our project a bit by taking advantage of subtemplates and includes.

Working with Multiple Templates

Level: Beginner

Duration: 9:46

In this lesson:

Creating a new page type

Let’s create our second template, based on home.html in our static site. In order to create a new page type, we first need to add a PHP class to represent it. Having a new class will give us the option of creating this page type in the CMS. Since this is code related, we’ll leave the theme folder for now, and add the file to the project directory, mysite/.

Create a file called HomePage.php in your mysite/code folder. Add the following content:

class HomePage extends Page {

}

class HomePage_Controller extends Page_Controller {

}

Both classes are deliberately empty, as they are just placeholders for the time being. Notice that we subclass the Page class so that we can inherit all of its properties and functionality, such as $Title, $Content, $Menu, etc. This first class is called the model. It will contain all of the custom database fields, data relationships, and functionality that can be expressed across multiple templates.

By convention, every page type is paired with a controller that follows the naming pattern [PageType]_Controller. The controller is the liaison between the HTTP request and the finalised template. Controllers can become very dense with functionality, and will commonly include functions for querying the database, handling form submissions, checking authentication, and dealing with an assortment of business logic.

Now that we have this new page type, it is necessary to rebuild the database so that the CMS is aware of its existence. Access the URL /dev/build on your website. When the script is complete, you should see some blue text indicating that the field SiteTree.ClassName was updated to include HomePage.

Let’s go into the CMS at the URL /admin, log in if necessary, and edit the page Home. On the Settings tab, change the Page type to Home Page. Save and publish.

Leave the CMS and reload the home page in your browser. You should see the default page type with the home page content.

Using the $Layout variable

Earlier in the tutorial we discussed the DRY principle which discourages repeating content. One glaring problem you may have noticed is that, as we add new page types, we’ll have to copy over a lot of content (e.g. the head, navigation, and footer) to each page, but with little variation, all of our templates are going to share this content. This type of outer content is often called the “chrome” or your site. To prevent the redundancy of chrome in each template, SilverStripe offers template layouts.

To illustrate how this works, let’s first find all the content that will not be common between our default page and our home page. A quick glance through the mockups reveals that everything between the closing </header> tag and the opening <footer> tag is unique content.

Highlight all of the content between </header> and <footer> and cut it into your clipboard. Replace all of that content with the variable $Layout.

Create a new template in templates/Layout called Page.ss. Paste the content from your clipboard into that file, and save.

Likewise, create a new template in the same location called HomePage.ss. Copy the content between </header> and <footer> in the themes/one-ring/static/home.html file to your clipboard and paste it into this file.

Any time we create a new template, we need to flush the cache, so append ?flush to the URL and reload. You should now see a distinct design for the Home page versus the other two pages.

It may seem trivial, but you’ve just achieved massive gains in efficiency and code organisation. Here’s how it works:

  • SilverStripe sees that you are requesting a URL for a page that uses the HomePage.ss template
  • It first looks in the main templates/ directory to find the chrome for this page. If it finds HomePage.ss in there, it will select that as your chrome. If not, it will go through the ancestry of that page type until it finds a match. It finds the parent class of HomePage, which is Page, and uses it.
  • The $Layout variable tells SilverStripe to look in the templates/Layout directory for a template that matches this page type. It finds HomePage.ss and uses it. If it had not found HomePage.ss, it would chase up the ancestry and find Page.ss, and use that as a fallback.

A vast majority of SilverStripe projects have only one template, Page.ss, in the root templates/, leaving everything else to Layout/. In some circumstances, you may have a page type that has such a distinct design that it needs its own chrome. A common example of this is a login page, where the user is presented with a very streamlined, isolated form.

Injecting assets through the controller

Right now, we have all the CSS and Javascript dependencies hardcoded in the template. This works okay, but often times you will benefit from handing over management of dependencies to the controller. This gives you the ability to require specific files for only certain pages as well as conditionally include or exclude files based on arbitrary business logic.

To include these dependencies, we’ll make a call to the Requirements class in our controller. Since these dependencies are common to all pages, we can add this to Page_Controller in Page.php.

Make the following update to the init() method.

public function init() {   
  parent::init();
  Requirements::css("http://fonts.googleapis.com/css?family=Raleway:300,500,900%7COpen+Sans:400,700,400italic");
  Requirements::css($this->ThemeDir()."/css/bootstrap.min.css");
  Requirements::css($this->ThemeDir()."/css/style.css");
  Requirements::javascript($this->ThemeDir()."/javascript/common/modernizr.js");
  Requirements::javascript($this->ThemeDir()."/javascript/common/jquery-1.11.1.min.js");
  Requirements::javascript($this->ThemeDir()."/javascript/common/bootstrap.min.js");
  Requirements::javascript($this->ThemeDir()."/javascript/common/bootstrap-datepicker.js");
  Requirements::javascript($this->ThemeDir()."/javascript/common/chosen.min.js");
  Requirements::javascript($this->ThemeDir()."/javascript/common/bootstrap-checkbox.js");
  Requirements::javascript($this->ThemeDir()."/javascript/common/nice-scroll.js");
  Requirements::javascript($this->ThemeDir()."/javascript/common/jquery-browser.js");
  Requirements::javascript($this->ThemeDir()."/javascript/scripts.js");
}

The only script we haven’t included is the html5 shim that is conditionally included for IE8. While it is possible to add conditional comments via the Requirements layer, it’s a bit of a hack, and since this is an edge case, we’ll just leave it as is in the template.

Next, remove all the <script> and stylesheet tags from your templates/Page.ss file.

Tidying up with includes

To keep our templates less dense and easier to work on, we’ll spin off parts of the template into the templates/Includes directory. Start by cutting the <div id=”top-bar” /> into your clipboard. Replace that entire div with <% include TopBar %>. The include declaration tells SilverStripe to look in the templates/Includes directory for a template with the name that you specified.

Create a file named TopBar.ss in templates/Includes and paste the content from your clipboard.

Repeat this process for <div id=”nav-section” />, and call the template MainNav.ss.

Repeat the process once again for the entire <footer /> tag, and call the template Footer.ss.

Lastly, remove all of the HTML comments from your Page.ss, as the template is now too sparse to require such guides.

Questions and Feedback

I am having issues with the Other Page Types Templates. My other templates do not show up. So for example, my Home Page will not display. I even went ahead and got to the Article Page Types and the same. The Page.ss template is the only one that will display. I have even deleted everything and started from the beginning again and still the same. I am using the most recent versions of SilverStripe, version v3.1.12. And I have carefully followed the lessons step by step.

Is there something else I need to do to get my other templates to route through the template/Page.ss. Right now every page is the same. Layouts/Page.ss -> Templates/Page.ss So HomePage.ss, ArticleHolder.ss will not display.

Thanks,

Darren

by Darren at 03:55pm, 26 March 2015

Author

Hi, Darren,

Did you remember to go into the CMS and change the page type from "Page" to "HomePage", "ArticlePage", etc?

by UncleCheese at 10:29am, 27 March 2015

Yes. I made changes to the Home Page from Page to HomePage Type.

by Darren at 01:35pm, 27 March 2015

I also download the files from the lessons after this lesson to see if I could get those to work. Again deleted my SilverStripe DB and all files. Reinstalled a brand new fresh SilverStripe and downloaded the lesson files and same issue. I am running a Windows 8 machine and I am using WampServer. Any ideas????

by Darren at 09:13am, 31 March 2015

Author

Hi, Darren,

Would you be able to send me a ZIP file of your site, so I can test it? [email protected]

By the way, nice avatar. I'm from the Boston area. :-)

by UncleCheese at 03:21pm, 1 April 2015

could you find what his problem was? because i'm having the same issue and i've been trying to get it working for more than a week, same as him i'm running in windows 8 with wampserver

by Nacho at 01:04am, 17 April 2015

The cause of my issues was incorrect naming conventions of my Layout and Includes folder.

by Darren at 01:44am, 18 April 2015

When i goto /dev/build, no blue text shows up for HomePage and it then doesn't show up on settings Page in /admin

by Rahul at 01:15pm, 5 April 2015

It worked :)

by rahul at 01:18pm, 5 April 2015

Author

Glad you got it sorted!

by UncleCheese at 03:16pm, 9 April 2015

If any of you are having trouble with Lesson 4 and are getting really frustrated, maybe my solution will help you out.

When I tried to implement the $Layout and have my content render from another page through the $Layout abstraction, it wouldn't appear. I thought this was very strange - maybe I didn't follow directions correctly. So I went through the tutorials three times to see if I missed a step. Nothing. I was badly in need of a Tylenol at this point and came to tackle the problem anew the following week.

I came up with another approach that might work for some of you, whether you attempt on Windows or Linux. (I didn't try on Mac - but it'd probably work there too.)

Instead of going through the tutorial and being stuck midway, I retemplated my files to look very similar to Lesson 5's zip file - linked here: http://github.com/silverstripe/one-ring-rentals/archive/lesson-5.zip .

Once I retemplated my own project files to be themed similarly, I was still getting the bizarre white screen of death. At this point, I knew that it wasn’t my own code’s logic anymore because it was nearly identical to Lesson 5's.

So I wanted to explore debug options. I assumed all my debug options were on (since my WAMP server has its own php.ini file and got errors before), but luckily UncleCheese wrote an article regarding debugging Silverstripe that I found immensely helpful. That article is here: http://www.leftandmain.com/silverstripe-tips/2010/09/08/8-common-silverstripe-errors-explained-and-solved/

So I turned on all of the debug options which I weren’t aware of in both .htacess and _config.php , and was promptly confused that none of it referenced any code within the files I wrote (except the $this->$MySite() ) - derp, but even fixing that still triggered the white screen of death.

So, I made another guess that it was because of my ending ?> PHP tags (that really threw me off, since it’s a strongly recommended practice to put that into PHP code).

At first, I thought the lack of ?> was a mistake within UncleCheese's code (or something that didn’t matter). But I saw it in a lot of files and noticed you mentioning it in that debug article, so I fixed it.

I removed those, turned on error reporting, ran a index.php/dev/build and a index.php?flush=1 . Lo and behold, the site was fixed.

Anyway, thank you very much for providing excellent documentation. It helped me solve my problem. Hopefully this comment helps the rest of you out there be more productive.

by Ryan at 11:12am, 3 July 2015

Hi,

I think it would be much better if in your tutorial description, you add information about which files are being edited.

For example, under subsection 'Using the $Layout variable', it is not clear which file are you referring to when you mention 'Highlight all of the content between and

and cut it into your clipboard.'.

This is especially helpful for some of us who cannot access the video.

by Fira at 08:18am, 18 August 2015

Hi,

I would like to bring your attention to something I've noticed. In the video, when you talk about the controller and injecting CSS using ThemeDir through the Requirements class, you use the syntax "{$this->ThemeDir()}/css/style.css", but here in the written tutorial you use another syntax which is $this->ThemeDir()."/css/style.css". I would like to know which one I should use. Are both usable or one is just an outdated syntax used in a previous version?

Thanks a lot,

by Samuel Carpentier at 09:05am, 5 November 2016

Hi,

Thank you for the lesson.

I have a problem at the very first step: When i goto /dev/build, no blue text shows up for HomePage and it then doesn't show up on settings Page in /admin.

Do you have any idea?

Thank you in advance.

by Trung Do at 07:09pm, 18 August 2017

Stuck on something? Have something to share? Don't be shy!

Keep learning!

Adding Dynamic Content

In this tutorial, we’ll start using SilverStripe’s native template syntax to inject dynamic content into our site, such as navigation, page titles, CMS content, and...

Migrating static templates into your theme

In this tutorial, we’ll migrate a static site into your SilverStripe project. HTML, CSS, and JavaScript will provide a nice common ground and starting point for...

Creating your first theme

In this tutorial, we’ll cover how to build your first theme in SilverStripe. The SilverStripe installer ships with its own default theme -- Simple, but more...