Introduction

Where to Start

WebPal Cloud Server is a pretty complex platform that can be daunting to explore at first login. With this documentation, we want to make first steps in application development as easy as possible. If you have not done so already, we recommend to read the instructions for basic web site editing and document management first. The next step is to get a good understanding of how WebPal site pages are rendered, followed by some more details on XSL transformations. Last not least, become a WebPal master by learning about extending site with custom code. 

WebPal Philosophy

WebPal Cloud Server is a Content Management and web application IDE in one. A devout WebPal developer subscribes to the philosophy that content and code can co-exist in a friendly manner.

In our world (of Pals), content editors, marketing professionals and client staff are able to collaborate on content edits while developers peacefully develop new functionality in an agile fashion.

We believe that developers should have access to advanced version control and can utilize their github accounts to synchronize code between multiple WebPal Servers, while content editors should be able to subscribe to the same mechanisms without having to learn the complexity of git commands to keep their content safe. 

WebPal Cloud Server manages account and content versions behind the scene to provide a safe environment for all involved.

 

Getting Started

Creating a New Site

The first step to develop a custom application is to create a Site. Assuming you have admin access to your WebPal Server, you can create a blank application under Web Sites > New.

To create a blank application without a predefined template, select the "BasicSite" template, and enter a new name for the application. 

The new site contains some placeholder content and pages that can easily be replaced. A publish destination is now required while the application is under development.

data?command=webpalimage.download&web_na

Granting Access

Only specific users are able to edit a site. You need to add access to the new site even for yourself, the user who just created the site. To do that, select add on the users table and select the users that should be able to access the site.

Note: at this time, there is just one level of access - all or none. We are adding different levels (edit, review, read-only, content-only, etc) in the near future.

data?command=webpalimage.download&web_na

You can now switch over to WebPal Sites data?command=webpalimage.download&web_na in order to start development and preview the application.

data?command=webpalimage.download&web_na

How WebPal Sites Work

Intro

Now that you have created a basic site, it's time to look a little under the hood. This chapter explains the inner workings of how pages of a WebPal Site are rendered and presented to the browser. This is very useful information if you are planning to extend the site's functionality with your own custom extensions.

Laravel Framework

WebPal uses Laravel as the model-view-controller (MVC) framework to handle all rendering, routing, and composition of pages within the site. So basically, a WebPal Site is a single, stand-alone Laravel Application. The code and resources for this application are all contained in a single extension called webpal-core, which is the cornerstone of every WebPal Site. Every site has this extension at a minimum.

Webpal-core contains a single core controller, routes, filters, resources, and a few other goodies that are explained further below. Although you can, you typically don't want to modify the webpal-core extension, as each of its functions can be extended or overridden using your own separate custom extension node. This approach will enable you to receive future updates to webpal-core without losing your own code.

XML Content Storage

In general, all content of a site is stored in hierarchical XML format, which creates a tree structure of nodes that can each be edited individually. Depending on the node's schema-type and other attributes, WebPal opens different editors to accommodate different content structures. What's important to note is that at all times, WebPal maintains nodes and content in perfectly valid XML. This enables us to always parse and transform the content using standard XSL transformations, but later more about that.

Attachments, such as images or other binary files, are stored as documents and referred to by the document file ID as generated by WebPal. This ID is generated every time a new attachment is inserted, pasted, copied or updated. 

Editors

As mentioned above, all node types have an attribute edittype that determines which editor UI is presented to the user when opening a node for editing. Currently, WebPal supports the following types: html, text, code, form, sheet, data-table, image, string, attributes.

data?command=webpalimage.download&web_na

Node Schemas

The webpal-core extension contains the schema which defines the structure of a basic WebPal Site:

<web>
 <pages>
  <page name="home">
  <html><h1>Home Page</h1><p>some text</p></html>
  </page>
 </pages>
 <extensions>
  <extension name="webpal-core">...</extension>
 </extensions>
</web>

This schema is defined by standard XML Schema Definition (XSD) language, which is stored in the extension's core-xsd node.

<element name="web" type="wpWeb"/>

<complexType name="wpWeb" edittype="sheet" icon="world.png" lockable="yes">
  <attribute name="name" use="required" type="wpName"/>
  <element name="settings" type="wpWebsettings" minOccurs="1" maxOccurs="1"/>
  <element name="pages" type="wpPageList" maxOccurs="1"/>
  <element name="extensions" type="wpExtensions" maxOccurs="1"/>
</complexType>

<complexType name="wpWebsettings" edittype="sheet" icon="wrench.png" lockable="yes">
  <element name="title" type="wpStringL"  minOccurs="1" />
  <element name="shorttitle" type="wpShorttitle"  minOccurs="1" />
  <element name="author" type="wpString"/>
  <element name="classification" type="wpStringL"/>
   ...
</complexType>

<complexType name="wpPageList" edittype="sheet" icon="folder_page.png">
  <element name="page" type="wpPage"/>
</complexType>

<complexType name="wpPage" edittype="sheet" icon="folder_page.png" lockable="yes">
  <attribute name="id" use="auto" type="wpString" value="chap"/>
  <attribute name="name" use="required" type="wpPageName"/>
  <attribute name="design" use="optional"  type="wpString"/>
  <attribute name="show-in-menu" use="oneof"  type="wpString" value="yes,no,sub-pages-only"/>
  <element name="page" type="wpPage"/>
  <element name="title" type="wpStringL"/>
  <element name="shorttitle" type="wpShorttitle" minOccurs="1"/>
  <element name="html" type="wpPageHtml"/>
   <!-- other possible child nodes here -->
</complexType>

 

It is thus possible to define entirely new node schemas that allow you to create virtually any content structure 

Transformations

Finally, webpal-core contains two nodes core-xsl and core-theme, which contain XSLT transformation stylesheets. XSL is a language which defines templates for transforming XML from one structure to another. XSL is a rule-based, not a functional language, and as such is ideally suited for the hierarchical nature of transforming XML content. It also offers convenient output switches to produce HTML and XHTML output formats.

For example, let's say we have a simple web site with this structure:

data?command=webpalimage.download&web_na  

<pages name="pages">
 <page name="home">
  <shorttitle>Home</shorttitle>
  <html>
   <h1>Home</h1>
   <p>Lorem ipsum dolor sit amet... </p>
  </html>
 </page>
 <page name="offers">
  <shorttitle>Our Offers</shorttitle>
  <page name="offer1">
   <shorttitle>Offer 1</shorttitle>
  </page>
  <page name="offer2">
   <shorttitle>Offer 2</shorttitle>
  </page>
  <page name="offer3">
   <shorttitle>Offer 3</shorttitle>
  </page>
 </page>
 <page name="contactus">
  <shorttitle>Contact Us</shorttitle>
 </page>
 <page name="common">
  <shorttitle>Common</shorttitle>
 </page>
</pages>

Then the following templates will render a basic navigation for this site. This template can be invoked in a number of different ways, later more about this. For now, let's assume that any XML content can be accessed and re-purposed for any page that is presented to the browser.

 <xsl:template match="page" mode="navigation">
  <xsl:param name="path" select="''"/>
  <li>
    <a href="{$path}/{@name}"><xsl:value-of select="shorttitle"/></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>

 

For more information on XSLT processing, we recommend you check out http://www.w3schools.com/xml/xsl_intro.asp 

Accessing Nodes

By default, all XSL transformations start with the root node of any input XML document as their main entry point of template matching. WebPal-core changes that by injecting any desired context node as the node to be processed. This node is located using an XPath expression. 

For example, let's say we want to render the home page of the sample site above. The corresponding XPath expression for the page to be rendered would thus be:

/web/pages/page[@name='home']

Webpal-core provides a single controller that bundles a number of methods for basic page-rendering functions. Among these is the Core::render() method which can be invoked as such:

\WebpalCore\Controllers\Core::render(
    array(
       'xpath' => "/web/pages/page[@name='home']"
      ));

Pre-processing and Caching

Generally, WebPal tries to store the entire web site in a single XML document for convenient XSLT processing. Naturally, for large web sites, this document can become rather large. This scaling concern is even larger for multi-lingual web sites which house duplicate version of the same content in different web sites or for different localities.

WebPal Sites use a multi-level caching cascade to optimize rendering performance of the final end-product, the page views. Additionally, the XML content is pre-processed, splitting the content into multiple copies for different languages. This pre-process is actually done by an XSLT transformation, too.

Lastly, the end-result of the final view computation is cacheable again by Laravel or edge-side proxy mechanisms, such as squid, redis, memcached, or mod_proxy.

Summarizing

Summarizing, the Core::render() method follows these steps:

1. Pre-processing

  • invoked whenever a new version of the site XML is published
  • splits the site XML into content, code, and separate attachment documents
  • splits the site XML into a version for each language
  • stores the results in Cache A

2. Transformation

  • invoked whenever a needed view is not in Cache B
  • retrieves the appropriate version of XML from Cache A, if present
  • extracts XSLT templates from the site XML and builds an XSLT processor from these
  • applies the XSLT to the XML, starting with the injected context node
  • stores the result in Cache B under a unique view name

3. Page Generation

  • invoked whenever a requested page is not in Cache C
  • identifies correct view name and retrieves the view from Cache B, if present
  • interprets the view as a Laravel Blade view
  • evaluates the view and substitutes variables
  • stores the result in Cache C (redis, proxy, or memcached)
  • presents the result page to the browser

4. Page Presentation

  • invoked whenever a page is requested
  • responds with page content from Cache C, if present

data?command=webpalimage.download&web_na  

Extensions

 

Adding an Extension

WebPal Sites have a simple mechanism to extend their functionality. Extensions nodes can be inserted under the extensions node. Palomino maintains a number of publicly available extensions on github which can easily be integrated into your web application project.

 

To import an extension into your site, select Import/Export > Import from Repository... from the context menu of the extensions node: 

data?command=webpalimage.download&web_na

Cloning from Github

To import (or clone) an extension from github into your site, all you need to supply is the SSH address of the extension's repository. You can copy this address from github using the "Clone with SSH" function:

data?command=webpalimage.download&web_na

Paste this address in the Import Node from Repository dialog. For convenience, the SSH key of your user account is supplied in this dialog. For public github repositories, this key is not needed, however it is necessary to access a private repository, such as on your own github account.

data?command=webpalimage.download&web_na

Makeup of an Extension

Once imported, the extension is visible as a new extension node. This node includes different components (resources, controllers, stylesheets, routes, and database), which usually do not need to be edited.

data?command=webpalimage.download&web_na

Most extensions supply additional nodes, which can be inserted on your site's pages. 

data?command=webpalimage.download&web_na

Templating with XSLT

Introduction

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/

XSLT in WebPal

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:

  1. XSL templates to transform static content as generated by the CMS, and subsequently,
  2. Laravel Blade templates to embed dynamic content generated by the application.

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.

data?command=webpalimage.download&web_na

The Default Page Template

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. 

Note
The XSLT processor simply concatenates all templates in the order as found in the Site XML. This generally does not affect the order in which templates are executed since XSL is a rule-based language and applies templates based on an order of specificity (most specific templates override less specific ones) and the priority attribute (see below).

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>

Overriding Default Templates

To override the default page-template supplied by webpal-core, you can supply custom templates with a higher priority value, like so:

  1. insert a new extension to contain your custom templates, and create a stylesheet node in it
  2. define a template that matches a page node, and assign it a priority higher than 0.1

The template should generate the HTML for an entire page, including the html, body and head tags:

Page Navigation

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:

  1. call a WebPal pre-defined macro render-content, which processes all page children
  2. processes the page structure in a different mode "navigation", which effectively calls the second template.

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.

Template Priorities

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.

Named 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.

 

Routing

Introduction

The webpal-core extension defines a set of default routes for rendering pages and serving resources. These are tested against the URL in order, and the first matching route is invoked. WebPal allows editing of routes with a convenient table view in order to manage larger numbers of routes easily.

Custom Routes

You can add custom routes by inserting a routes node in an extension like so:

Routes are matched against the URL in order specified, which means that to override existing routes, your custom extension should be placed before the webpal-core extension in order for the custom routes to be matched first.

Calling A Template

A pre-defined route can be used to call specific named templates. For example, assume you wrote a template as such:

<xsl:template name="my-custom-sitemap">
 <html>
  <h1>Sitemap</h1>
  <xsl:apply-templates select="/web/pages/page" mode="navigation"/>
 </html>
</xsl:template>


 

you can now invoke it with this route:

/call-template/my-custom-sitemap

Caution: this default route allows anyone to invoke your named templates. Thus, all named templates should ensure that they do not expose the entire XML or any protected pages to the browser. For example, the following named template copies the entire XML, including settings, and code nodes, to the browser.

<xsl:template name="not-a-good-template">
  <xsl:copy-of select="/web" />
</xsl:template>


 

Disabling Default Routes 

If you need to disable any of the default routes, simply override them with new behaviour in your custom extension. For example the following route will redirect the call-template URL to the home page:

data?command=webpalimage.download&web_na

Resources

Introduction

Any site extension can supply it's own set of resources, such as images, CSS or Javascript files. The webpal-core extension only supplies a minimal set of default resources, as we attempted to make the core as light-weight as possible. 

Resources

All resource files are managed under the resources node - which behaves exactly like a document folder. Files here can be edited (double-click to open), copied, deleted, and so on. Adding a file here allows you to reference it via a special resource route (which is defined in webpal-core):

<link rel="stylesheet" href="/resources/ext/CamelBackExtensionName/path/to/resource.css" />

Note the CamelBack version of the extension name. To achieve a consistent and compatible naming convention for storage of extension resources and the equivalent namespaces, extension names are converted to CamelBack - ignoring all non-alpha characters and treating them as separators instead.

Resource Links

In many cases, you want the page templates to includes additional resources supplied by the extensions without having to declare these each time in the page-template. To auto-include required resource links, you can declare these resources in the resource-links node, like so:

The link pathname to be supplied should not be absolute. For example, if the resources file mystyles.css is in the css folder under the resource node, then the pathname to supply is:

css/mystyles.css

Note that this also allows you to declare external resources, simply by supplying the full URL instead of the relative pathname, for example:

https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css

Auto-including Resources

Once required resource links are defined by your extensions, you can generate the include statements with a single call to include-extension-styles and include-extension-scripts templates pre-defined in webpal-core:

<xsl:template match="/web/pages//page"
                mode="page-template">
  <html lang="en">
     <head>
       <title>Basic WebPal Site</title>
    <!-- include all styles -->
    <xsl:call-template name="include-extension-styles"/>
     </head>

     <body>
      ...
   </body>

   <!-- include all scripts -->
   <xsl:call-template name="include-extension-scripts"/>

 </html>
</xsl:template>

This template generates <link> and <script> tags for all resource links, in document order.