WebPal stores all app content as XML, and, offers XSLT transformations to process the content into HTML. This model allows you to maintain both content and templating instructions in a single user interface.
Even moreso, since XSL is itself a language that can be written in XML, it is maintained within the tree structure of a web site. There are a number of advantages to this combined storage of content and templates, last not least being the ability to extend templates very easily.
This chapter assumes you have an basic knowledge of the XSL and the XSLT templating language. We recommend some reading at http://www.w3schools.com/xsl/
Below a visual diagram of how the UI maintains content (XML) and templates (XSL) jointly and the XSLT processor uses the XSL instructions to generate a blade template for the Laravel App to consume. So, in short, WebPal uses:
The webpal-core extension supplies a set of default XSL templates to the processor, which can be overridden by supplying additional templates with a higher priority value. This means that as a CMS developer, you can use XSLT templates to define how static content is rendered on the current page to display.
During the Transformation step of a page load, a new XSLT Processor object is created which is initialized with all XSL stylesheets and templates defined within the Site extensions. XSL stylesheets are added to an extension simply by selecting Insert new... > stylesheet for the extension node.
After initializing, the processor by default applies templates starting with the root node of the site XML document, with is the top-level web node. Since this is in most cases not the desired behaviour, the Core::render() controller method injects the desired starting node using the $NODE parameter, and then applies the best matching template in the mode page-template.
<xsl:template match="/" priority="0.1">
<xsl:if test="$NODE">
<xsl:for-each select="$NODE">
<xsl:apply-templates select="." mode="page-template"/>
</xsl:for-each>
</xsl:if>
</xsl:template>
To override the default page-template supplied by webpal-core, you can supply custom templates with a higher priority value, like so:
The template should generate the HTML for an entire page, including the html, body and head tags:
Now let's create a couple of simple templates that render the pages in a two-column layout, and adds a nested list of navigation links in the left sidebar.
<xsl:template match="/web/pages//page"
mode="page-template"
priority="0.5">
<html lang="en">
<head>
<title>Page Title</title>
</head>
<body>
<table>
<tr>
<td colspan="2">
<h1>Basic WebPal Site</h1>
</td>
</tr>
<tr>
<td style="width:300px; vertical-align: top; padding: 10px;">
<ul>
<xsl:apply-templates select="/web/pages/page" mode="navigation"/>
</ul>
</td>
<td style="width: 600px; padding: 20px;vertical-align: top; ">
<xsl:apply-templates select="*"/>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="page" mode="navigation">
<xsl:param name="path" select="''"/>
<li><a href="{$path}/{@name}"><xsl:value-of select="@name"/></a></li>
<xsl:if test="page">
<ul>
<xsl:apply-templates select="page" mode="navigation">
<xsl:with-param name="path" select="concat($path, '/', @name)"/>
</xsl:apply-templates>
</ul>
</xsl:if>
</xsl:template>
The first template defines a simple page with a table-based layout, and does two things:
The second template recursively builds a simple navigation menu with links to all pages of the site. View the result by navigation to the "home" page and tapping "Preview".
Let's say that for all pages other than the home page, you want to use a 3-column layout. To achieve this without modifying your existing templates, you can add another template with higher specificity like so:
<xsl:template match="page[@name != 'home']"
mode="page-template">
<html lang="en">
<head>
<title>Basic WebPal Site</title>
</head>
<body>
<table>
<tr>
<td colspan="3">
<h1>
Basic WebPal Site
</h1>
</td>
</tr>
<tr>
<td style="width:300px; vertical-align: top; padding: 10px;">
<ul>
<xsl:apply-templates select="/web/pages/page" mode="navigation"/>
</ul>
</td>
<td style="width: 600px; padding: 20px;vertical-align: top; ">
<xsl:call-template name="render-content"/>
</td>
<td style="width:300px; padding: 20px; vertical-align: top; ">
<xsl:apply-templates select="/web//page[@name='common']/html"/>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
This template will take precedence over the default behaviour for all page nodes that don't have a @name of 'home' and results in this layout:
Obviously, the same can also be achieved in other ways. For example, the default behaviour can be defined as a 3-column layout, and only the home page uses a different template.
You can define a template priority like so:
<xsl:template match="page" mode="page-template" priority="0.75">
The priority attribute ranges from 0.0 to 1.0, with 0.5 being the default. The default priority for all templates is 0.5. The webpal-core extension uses priority 0.1 for it's default templates.
The XSL standard prescribes that named templates of the form <xsl:template name="some-template"> need to be globally unique for the entire stylesheet.
Since there are a number of templates provided by other extensions, a naming convention of pre-pending the extension name is recommended, for example my-custom-ext--my-named-template.