MarcusEdwards
Crownpeak (Retired)

Why you should be using the Master Page pattern

Introduction

When you first start an implementation on Crownpeak, one of the first things you'll need to do is identify the shared elements across all the pages on your site -- typically this is the header and footer areas.nav wrapper extraction.png

 

Rather than have the header and footer configuration entered by the content editor on every page, the content and the design is extracted out and put into a "nav wrapper" that is then included in the output form each page template using the Out.Wrap Template API call.

The result is that when pages are published from the CMS to the content delivery environment, the files that are delivered look like the ones from the design, with the header and footer inserted at publish-time by the CMS.publishing with nav wrapper.png

 

The challenge

This is very convenient but does suffer from one problem: what happens if we need to make a change to the content or the design of the nav wrapper elements? The changes to the template code are convenient because we only have one template to change. Similarly, any content changes only need to be made to one content asset. However, it does mean that we need to republish every page on the site so that the changes can be integrated.

The CMS can handle publishing jobs like this without any problems at all -- we have seen publishing queues with tens of thousands of assets in them. However, there is a timing problem: while the publishing is happening, visitors to your site may have an inconsistent experience: seeing the updates on some pages and not others until the publishing job completes. It also means that any other content changes may be stalled while waiting for the publishing job to complete.

The way to solve this is to take advantage of server-side technologies on the content delivery side. We will publish out the nav wrapper as an independent asset and change the content template output to include the nav wrapper at or near content request time. Generically we refer to this as a master page pattern.publishing with master page.png

 

Depending on the technology available in the content delivery environment, there are a number of ways you could implement this pattern. Let's look at two simple ones:

  • ASP.Net Master Pages (Web Forms)
  • JSP Tag Library

I've picked these two as these technologies are available on the Crownpeak hosting servers and they are simple enough that we can use them without having to introduce more complexity than necessary.

ASP.Net Master Pages

ASP.Net Web Forms was included in the original .NET Framework 1.0 release in 2002, which supported Web Application projects and Web Site projects. But it was the introduction of Master Pages in 2005 that we're interested in here.

An ASP.Net Master Page contains ASP.Net markup declaring the page as a master page and marking up content placeholders that content pages could then supply content for -- an almost perfect implementation of the concept described in the introduction.

The nav wrapper template is updated to output ASP.Net Master Page markup. A content asset is made using this template and published as "site.master" for example (the .master extension is important as the default configuration in IIS is set up to recognise this).

Content page templates are updated to output ASP.Net Page markup, crucially including a reference to the master page to use.

Here is an example of an ASP.Net Master Page

<%@ Master Language="C#" AutoEventWireup="true" %>
<!DOCTYPE html>
<html>
  <head>
    ...
    <asp:ContentPlaceHolder runat="server" ID="Header" /> 
  </head>
<body>
  ...
  <div class="page" id="page">
    <div role="main"><asp:ContentPlaceHolder runat="server" ID="Body" /></div>
  </div>
  ...
  <footer class="footer">
    <asp:ContentPlaceHolder runat="server" ID="Footer" />  
  </footer>
</body>
</html>

What you'll notice is the master page declaration in line 1 and the <asp:ContentPlaceHolder.../> declarations in the markup.

And here is the output from a content page, an article in this case:

<%@ Page Language="C#" AutoEventWireup="true" MasterPageFile="site.master" %>
<asp:content runat="server" contentplaceholderid="Header">
    <title>Sample Article</title>
    <meta name="title" content="Sample Article"/>
    <meta name="description" content="Luin le imlad thavron amarth roch yanta avari bereth alph alata sein meleth."/>
</asp:content>
<asp:content runat="server" contentplaceholderid="Body">
    ...
</asp:content>

The key elements here are the reference to the master page file in the page declaration on line 1; and the definition of the content elements with the contentplaceholderid specifying which placeholder in the master page the content is targeting. Note: you don't have to provide content for all placeholders -- we didn't provide and footer content in this example.

That is all that is necessary to implement this pattern: no other dependencies, no changes to the CMS structure or pre-compilation necessary. There are certainly more modern ASP.Net alternatives like MVC and CSHTML (Razor) that you could use just as effectively, but they would impose further changes on the output and crucially the CMS content structure.

JSP Tag Library

Implementing the Master Page pattern in JSP is very similar but doesn't explicitly use the term "master page". Instead JSP Tag Library approach uses the notion of pages and fragments. The nav wrapper template is updated to output a JSP tag -- this must be published to the WEB-INF/tags folder on the content delivery servers. The nav wrapper will reference "fragments" as variables that the content pages will provide.

Here is the equivalent tag definition for the master page we looked at in the previous section. This is published as WEB-INF/tags/master.tag:

<%@tag description="master page" pageEncoding="UTF-8"%>
<%@attribute name="header" fragment="true" %>
<%@attribute name="footer" fragment="true" %>
<!DOCTYPE html> 
<html lang="en">
  <head>
    ...
    <jsp:invoke fragment="header"/>
    ...
  </head>
<body>
  ...
  <div class="page" id="page">
    <div role="main"><jsp:doBody/></div>
  </div>
  ...
  <footer class="footer">
    <jsp:invoke fragment="footer"/>
  </footer>
</body>
</html>  

The key elements here are:

  • The tag declaration on line one
  • Declaration of the placeholders as fragments (lines 2-3)
  • Insertion of the placeholders / fragments using the jsp:invoke

The content templates need to be changed to output something like this:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>
<t:master>
    <jsp:attribute name="header">
    ...
    </jsp:attribute>
    <jsp:body>
    ...
    </jsp:body>
</t:master>    

The important elements here are:

  • Setting up the namespace prefix 't' to point to the tags folder under WEB-INF
  • Referencing the master tag by name: <t:master> will match up to the master.tag file we published for the master page
  • Using <jsp:attribute> tags to set up the content areas that will be inserted into the master tag
  • Using <jsp:body> as the default (unnamed) content areas that will be inserted in the <jsp:doBody> placeholder in the master tag

Summary

So there you have it, two implementations of the Master Page pattern in different technologies. Of course there are many other ways that you could solve the underlying problem, and perhaps with technology that is more modern. We use the implementations shown here because they impose the smallest change on a standard DXM implementation.

Labels (1)

Can't find what you are looking for?

Find Answers

Search our DXM Forum to find answers to questions asked by other DXM users.

Ask a Question

No luck? Ask a question. Our Product and Support teams are monitoring the Forum and typically respond within 48 hours.

Ask a Question