Journal

2 January 2007

Building a Symphony Theme: Part 3

Continuing on in the series on Building a Symphony Theme (see Part 1 and Part 2), I will start to introduce some dynamic elements.

Just to review, we have set up a virtual host, installed Symphony, set System Preferences and Author Settings, installed and enabled a Campfire Service, created a Page template and a Master template, and looked around the ?debug interface to view the XML data, XSLT templates and XHTML Output.

Before we start integrating our XHTML structure and CSS files, let’s get aquainted with the basics of working with Symphony and XSLT.

XSLT Parameters

First, there are several XSL parameters that can be used to start making our page template dynamic. You can find a list of these parameters by navigating to the home page and adding ?debug to the end of the URL in the address bar.

                  http://sym.qwilm.site/?debug

                

Click on the XSLT link at the top of the ?debug page and you will see a list of XSL parameters.

?debug XSLT view: XSL Parameters

Default Parameters

We can use these parameters within our page templates. Let’s start by adding the name of the site to the default Master template that we have created. Take a look at the list of parameters:

                  <xsl:param name="root" select="'http://sym.qwilm.site'" />
<xsl:param name="workspace" select="'http://sym.qwilm.site/workspace'" />
<xsl:param name="current-page" select="'home'" />
<xsl:param name="page-title" select="'Home'" />
<xsl:param name="parent-page" select="'/'" />
<xsl:param name="today" select="'2006-12-10'" />
<xsl:param name="website-name" select="'qwilm'" />
<xsl:param name="symphony-build" select="'1506'" />
<xsl:param name="url-mode" select="'full'" />
<xsl:param name="url-type" select="'page'" />
<xsl:param name="url-handle" select="''" />

                

For the moment, let me just state that the last three parameters that refer to url are not available for inclusion in your templates (for reasons I won’t get into here). The rest act as default parameters, generated by Symphony for every page, that can be called from within your template.

For example, the $website-name parameter uses the System Preference for Website Name. If you change this preference, this will change the value of $website-name wherever you have it in your templates.

The $root parameter refers to the domain that is used when installing Symphony. This value is stored in the /conf/config.php, which stores the information that is required for Symphony to access your database and to access the Symphony support server for updates.

We can use these two parameters to create a website name that links to the home page. Go to Blueprints : Components and click on default.xsl under Masters to edit the template. Symphony creates a default stylesheet that looks like this:

                  <?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
    method="xml" 
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
    omit-xml-declaration="yes"
    encoding="UTF-8" 
    indent="yes" />
<xsl:template match="/">
    <html>
        <head>
            <title><xsl:value-of select="$page-title"/></title>
        </head>
        <body>
            <xsl:apply-templates/>
        </body>
    </html>
</xsl:template>
</xsl:stylesheet>

                

We will want to change it to look like this:

                  <?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
    method="xml" 
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
    omit-xml-declaration="yes"
    encoding="UTF-8" 
    indent="yes" />
<xsl:template match="/">
    <html>
        <head>
            <title><xsl:value-of select="$page-title"/></title>
        </head>
        <body>
            <h1>
                <a href="{$root}/" title="Home Page">
                    <xsl:value-of select="$website-name"/>
                </a>
            </h1>
            <xsl:apply-templates/>
        </body>
    </html>
</xsl:template>
</xsl:stylesheet>

                

You should now be able to navigate to your home page and view a page that has a link to the home page. So, what just happened here? Well, there is a different syntax for finding values using XSLT depending on whether the value must be output within an element attribute or as the value of an element. For the anchor value <a>Value</a> we need to use a <xsl:value-of select="$param"/>, but for the attribute value <a href="value"></a> we need to use {$param}.

You might have noticed that the default Master template includes the $page-title parameter in the title element of the head element. It might also be a good idea to include this value as a page title in the body. Let’s add this value as an h2 to the xsl:template.

Add this after the h1 element:

                  <h2><xsl:value-of select="$page-title"/></h2>

                

So the xsl:template element looks like this:

                  <xsl:template match="/">
    <html>
        <head>
            <title><xsl:value-of select="$page-title"/></title>
        </head>
        <body>
            <h1>
                <a href="{$root}/" title="Home Page">
                    <xsl:value-of select="$website-name"/>
                </a>
            </h1>
            <h2><xsl:value-of select="$page-title"/></h2>
            <xsl:apply-templates/>
        </body>
    </html>
</xsl:template>

                

Default Data Sources

In addition to the default parameters, there are also default data sources available even before the creation of new sections and custom fields. While it is necessary to create new Data Sources to add the default data to the XML data for a page, the following are a list of the available sources:

  • Authors
  • Comments
  • Navigation

The Authors data is extracted from the Settings : Authors section.

The Comments data is extracted from the Publish : Comments section.

The Navigation data is extracted from the Blueprints : Pages section.

There is also a Static XML source for adding another child node to the XML data apart from the data stored in the database. So, for instance, you could create a node for the months of the year without having to create a section and custom fields for storing this data in the database.

Custom Data Sources

When you create a Data Source, you are actually creating a PHP file that is stored in the /workspace/data-sources/ directory. This PHP file extracts data from the MySQL database and outputs the data as XML so Symphony can use XSL templates to transform that XML data into HTML Output. To view the XML data associated with a page, view the ?debug information for the page.

Under the Publish menu, there are two menu items by default: Comments and File Manager. Every section that you create has an option to include comments, so that you can enable commenting for blog entries or for photo gallery entries, for instance. Implementing Comments will require attaching an Event, so I will tackle the basics before venturing into the more advanced features of Symphony.

Create a New Data Source: Navigation

The Navigation Data Source is the most basic to implement and one of the most useful. So let’s try this first. Go to Blueprints : Controllers.

Symphony Admin : Blueprints : Controllers

Click on the Create New button beside the Data Sources heading. On the New Data Source page, under Essentials, give the Data Source a Name: Navigation, and choose Navigation under the Source pull-down menu and click on the Save button.

Symphony Admin : Blueprints : Controllers : Data Sources : Create New : Navigation

Associate a Data Source with a Master template

To use this new Data Source, it must be associated with a page template or master template. Go to Blueprints : Components and choose the default template under Masters. Click on the configure button to view the Master Settings, and click on Navigation in the select box under Data Source XML in the Master Environment. (You can select multiple Data Sources by using the command button on the Mac and the control button in Windows.)

Symphony Admin : Blueprints : Components : Masters : default : Configure

To see the effect of this change, let’s create a couple pages first. Go to Blueprints : Pages and click on the Create New button. Add two pages: one with the name, About, and the other with the name, Contact. You won’t need to configure these pages as we did with the home page, since Symphony will automatically create these pages with a type of “default” and a handle that corresponds with the name of the page. Now, view the Home page by clicking on the front page link, the name of the site beside the Symphony logo in the top of the Symphony Admin. View the ?debug information for the page to see the XML data created by the Navigation Data Source.

Navigation XML Data

Using XSLT to transform XML data into HTML output

The XML data now contains a node element called “navigation”.

                  <?xml version="1.0" encoding="utf-8" ?>
<data>
    <events />
    <navigation>
        <page handle="home" type="index">
            <title>Home</title>
        </page>
        <page handle="about" type="default">
            <title>About</title>
        </page>
        <page handle="contact" type="default">
            <title>Contact</title>
        </page>
    </navigation>
</data>

                

Now that we have some data to work with, it is possible to tranform this XML data with our default XSL template into HTML output that will be displayed on pages that use the default template. Next, let’s discover how the transformation happens. It makes sense to start with some sort of navigation to be able to move from one page to another on our site.

The XPath Language

The XML data contains values that we will want to display on our page. The XPath language is the means by which XSL extracts values from XML data. An XSLT template establishes patterns for generating HTML output that uses the values extracted from the XML data. Mark Lewis provides a good overview of Symphony’s role in the XSLT process in his Overture article, A Symphony Walkabout. To help you get started with XML, XPath and XSLT, you can find other resources in the Overture Wiki.

In Symphony, the root element of the XML data is always the <data/> element. For each data source that you associate with a page, a child node will be added to the data element. The name of the node will correspond to the name you created for the Data Source except that the name will consist only of lowercase letters with spaces replaced by hyphens.

Create the Navigation Menu

To create the main navigation for the site, we can start by creating an unordered list of links for each of the main sections. So far, we have three pages: Home, About and Contact. It would be fairly easy to create the list without relying on XSLT to do the job. The menu might look something like this:

                  <ul>
    <li><a href="http://sym.qwilm.site/home/">Home</a></li>
    <li><a href="http://sym.qwilm.site/about/">About</a></li>
    <li><a href="http://sym.qwilm.site/contact/">Contact</a></li>
</ul>

                

This would be fine if we only had three pages to deal with, but if we had several sections, each with multiple pages per section, the reasons for having a means of dynamically creating the menu become clearer. For now, we’ll keep things simple.

It helps to have our intended output figured out before generating the XSL template. So, let’s use the structure above for dynamically generating the menu, starting with the Home page. When we take a closer look at the XML data, we find that the root node “data” contains a node for “navigation” which contains three child “page” elements. Each of the “page” nodes has two attributes: “handle” and “type”. Each page node has a single child element: “title”. To output the value of an element or attribute, we will use XPath to select the value and the <xsl:value-of/> element to output the value of the HTML element or the {...} to output the HTML element attribute.

The context node is defined by the match value in the <xsl:template/> element for the default template.

                  <xsl:template match="/">

                

In this case, it is the root of the XML data, as indicated by "/". An absolute path expression would begin with "/" to indicate the location of the node relative to the root of the XML data. A relative path expression would begin with something other than "/" to indicate a location relative to the context node. For our default Master template, to find the value of the page node, we can use a relative path expression:

                  data/navigation/page

                

For example, to display the value of the first page in the navigation, we could use the following expression:

                  <h2><xsl:value-of select="data/navigation/page/title"/></h2>

                

Add this to the default template and see what happens by viewing the home page (and the ?debug information, if you are curious):

                  <?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
    method="xml" 
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
    omit-xml-declaration="yes"
    encoding="UTF-8" 
    indent="yes" />
<xsl:template match="/">
    <html>
        <head>
            <title><xsl:value-of select="$page-title"/></title>
        </head>
        <body>
            <h1>
                <a href="{$root}/" title="Home Page">
                    <xsl:value-of select="$website-name"/>
                </a>
            </h1>
            <h2><xsl:value-of select="data/navigation/page/title"/></h2>
        </body>
    </html>
</xsl:template>
</xsl:stylesheet>

                

Notice how this outputs only the first page. In fact, the expression we are using could apply to any of the three pages in the XML data, but the <xsl:value-of/> element can output only a single value, so it defaults to the first element that it finds. How can we output the second page? We can use a predicate to evaluate and filter the node-set based on various criteria, including position in the document order. The second page element can be selected with the following code:

                  <h2><xsl:value-of select="data/navigation/page[position()=2]/title"/></h2>

                

This can also be expressed in shorthand syntax:

                  <h2><xsl:value-of select="data/navigation/page[2]/title"/></h2>

                

Or try the following to output the title of the third page:

                  <h2><xsl:value-of select="data/navigation/page[3]/title"/></h2>

                

If we wanted to output all three at once, we need to use <xsl:for-each/> to apply the same template for each of the elements that matches the selection criteria.

                  <xsl:for-each select="data/navigation/page">
    <h2><xsl:value-of select="title"/></h2>
</xsl:for-each>

                

This template is saying, effectively, “for each page in the navigation, output the title as a second-level heading.” Notice how the “page” element is selected by the for-each “select” attribute and how the <h2> element contains the “title” value.

What we really want is an unordered list, so we need a template that looks more like this:

                  <ul>
    <xsl:for-each select="data/navigation/page">
        <li><xsl:value-of select="title"/></li>
    </xsl:for-each>
</ul>

                

Notice how the <ul> element is outside the <xsl:for-each> element, since we don’t need a separate unordered list for each page. Rather, we need three pages to be listed in a single unordered list.

This menu will not be very useful until we have included a link to each page. That is where the “handle” attribute comes in. Each page has a “handle” attribute that represents the title of the page converted to a URL handle by rendering the title in lowercase letters and replacing spaces with hyphens. With XPath, attributes are selected with the “@” symbol as in the following expression:

                  <xsl:value-of select="data/navigation/page/@handle"/>

                

However, when the value is output within an attribute of a HTML element, a different XSL syntax is required, called an Attribute Value Template (AVT), using curly braces:

                  <a href="{data/navigation/page/@handle}">Page Title goes here</a>

                

Within the context of our navigation list, the template should look like this:

                  <ul>
    <xsl:for-each select="data/navigation/page">
        <li><a href="{@handle}"><xsl:value-of select="title"/></a></li>
    </xsl:for-each>
</ul>

                

This will work fine if we want relative URLs, but we might want absolute URLs, especially if Symphony has been installed somewhere other than the root web directory. In this case, default parameter for the site root will be very useful: $root. As mentioned before, the value of the $root parameter is determined during the installation of Symphony and is stored in the conf/config.php file. It determines the URL for the front page of your site. You can include this parameter in a link as an attribute value:

                  <ul>
    <xsl:for-each select="data/navigation/page">
        <li><a href="{$root}/{@handle}/"><xsl:value-of select="title"/></a></li>
    </xsl:for-each>
</ul>

                

You should now be able to navigate from page to page.

Using conditionals to display the current page

Now, the power of Symphony and XSLT shines in being able to dynamically determine the current state of a web page. Going back to our list of default parameters, we will find another tremendously useful parameter: $current-page. This is the value of the handle of the current page. As you navigate from one page to another, add ?debug to the end of the address bar and click on the XSLT link to view the changes to the $current-page parameter. With CSS, it is possible to apply a class attribute to a list item to display a different style for a current link. Add the following <style> element to the <head> element of the default template:

                  <style type="text/css">
    li.current a {color:#f00; text-decoration:none;}
</style>

                

Add a class attribute to the list item for the navigation menu:

                  <li class="current">

                

The default template should now look like this:

                  <?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
    method="xml" 
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
    omit-xml-declaration="yes"
    encoding="UTF-8" 
    indent="yes" />
<xsl:template match="/">
    <html>
        <head>
            <title><xsl:value-of select="$page-title"/></title>
            <style type="text/css">
                li.current a {color:#f00; text-decoration:none;}
            </style>
        </head>
        <body>
            <h1>
                <a href="{$root}/" title="Home Page">
                    <xsl:value-of select="$website-name"/>
                </a>
            </h1>
            <ul>
                <xsl:for-each select="data/navigation/page">
                    <li class="current"><a href="{$root}/{@handle}/"><xsl:value-of select="title"/></a></li>
                </xsl:for-each>
            </ul>
        </body>
    </html>
</xsl:template>
</xsl:stylesheet>

                

All of the items in the menu list should now be colored red with no underline. This is not quite what we are after, since we want to apply this style only to the link that represents the current page. We can do this by using a conditional XSL element. XSLT allows for the ability to choose elements based on certain conditions. There are a couple different conditional elements: <xsl:if> and <xsl:when>. Each of these elements tests for a certain condition, and, if the test is successful, will output whatever is contained within the element.

If we want to test whether a link matches the current page, we can use the <xsl:if> element like this:

                  <ul>
    <xsl:for-each select="data/navigation/page">
        <xsl:if test="@handle = $current-page">
            <li class="current">
                <a href="{$root}/{@handle}/">
                    <xsl:value-of select="title"/>
                </a>
            </li>
        </xsl:if>
    </xsl:for-each>
</ul>

                

The <xsl:if> element tests whether the value of the handle of the <page> element in the XML data matches the URL handle of the current page indicated by the value of the default page parameter $current-page.

We can also test whether a page handle does not match the current page handle with another <xsl:if> element by using the operand “!=”, which means “does not equal”:

                  <xsl:if test="@handle != $current-page">

                

We simply remove the “current” class attribute from the list item when the page handle does not match the $current-page parameter:

                  <ul>
    <xsl:for-each select="data/navigation/page">
        <xsl:if test="@handle != $current-page">
            <li>
                <a href="{$root}/{@handle}/">
                    <xsl:value-of select="title"/>
                </a>
            </li>
        </xsl:if>
    </xsl:for-each>
</ul>

                

Try navigating from page to page and you’ll see the effect. Using the <xsl:if> twice is not very efficient, since each element has to be tested twice. The <xsl:when> element allows us to perform an “if, then” sort of statement. The <xsl:when> element must always be contained by a <xsl:choose> element, and can sometimes be accompanied by a sibling <xsl:otherwise> element. So we can accomplish the same result as the two <xsl:if> elements with the following XSL code:

                  <ul>
    <xsl:for-each select="data/navigation/page">
        <xsl:choose>
            <xsl:when test="@handle = $current-page">
                <li class="current">
                    <a href="{$root}/{@handle}/">
                        <xsl:value-of select="title"/>
                    </a>
                </li>
            </xsl:when>
            <xsl:otherwise>
                <li>
                    <a href="{$root}/{@handle}/">
                        <xsl:value-of select="title"/>
                    </a>
                </li>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</ul>

                

This code is saying, when the page handle matches the current page handle, output the title of the page as a list item with a class attribute of “current” and with a link to the associated page; otherwise, output the linked page title as a list item with no class attribute. Now, each <page> node is tested only once.

Create a Navigation Template

We can reuse this code in other template by creating a named template that can be called from other XSL templates. In Symphony, these templates can exist as Utilities, Page templates or Master templates. We can also add another template to the default Master template.

                  <?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
    method="xml" 
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
    omit-xml-declaration="yes"
    encoding="UTF-8" 
    indent="yes" />
<xsl:template match="/">
    <html>
        <head>
            <title><xsl:value-of select="$page-title"/></title>
            <style type="text/css">
                li.current a {color:#f00; text-decoration:none;}
            </style>
        </head>
        <body>
            <h1>
                <a href="{$root}/" title="Home Page">
                    <xsl:value-of select="$website-name"/>
                </a>
            </h1>
            <xsl:call-template name="navigation"/>
        </body>
    </html>
</xsl:template>
<xsl:template name="navigation">
    <ul>
        <xsl:for-each select="data/navigation/page">
            <xsl:choose>
                <xsl:when test="@handle = $current-page">
                    <li class="current">
                        <a href="{$root}/{@handle}/">
                            <xsl:value-of select="title"/>
                        </a>
                    </li>
                </xsl:when>
                <xsl:otherwise>
                    <li>
                        <a href="{$root}/{@handle}/">
                            <xsl:value-of select="title"/>
                        </a>
                    </li>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </ul>
</xsl:template>
</xsl:stylesheet>

                

The named template can be called within another XSL template within the same stylesheet by using this code:

                  <xsl:call-template name="navigation"/>

                

Create a Utility

In Symphony, a Utility can be created to include a template or a group of templates within the XSL stylesheet. Go to Blueprints : Components and click on the “Create New” button next to Utilities. A new Utility contains the <xsl:template> element to get you started. Give the Utility the name “Main Menu” and paste the following into the Body of the Utility:

                  <xsl:template name="main-menu">
    <ul>
        <xsl:for-each select="data/navigation/page">
            <xsl:choose>
                <xsl:when test="@handle = $current-page">
                    <li class="current">
                        <a href="{$root}/{@handle}/">
                            <xsl:value-of select="title"/>
                        </a>
                    </li>
                </xsl:when>
                <xsl:otherwise>
                    <li>
                        <a href="{$root}/{@handle}/">
                            <xsl:value-of select="title"/>
                        </a>
                    </li>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </ul>
</xsl:template>

                

This is the same template we have in our default Master template, except that the name of the template is “main-menu”. Click on “Navigation” in the Associate with Data Source select box and click on the Save button. (Note that the image below doesn’t show the same template that we have above.)

Symphony Admin : Blueprints : Components : Utilities : Main Menu

We have already associated the Navigation Data Source with the default Master template, so we can go to the default Master template (Blueprints : Components : Masters : default) and change the <xsl:call-template> element:

                  <xsl:call-template name="main-menu"/>

                

View the front page of your site and you will see the same thing we had before, except that the template is being read from the template named “main-menu” stored in the “Main Menu” Utility. You can change the name of the Utility to “Navigation” and because the Utility is associated with the Navigation Data Source, the “main-menu” template will still be included in the stylesheet for the pages associated with the default template. At this point, it is possible to delete the “navigation” template from default Master template. We can do this without using the Symphony Admin. Find the location of the default.xsl file where you installed Symphony. My file is located here on my hard drive:

                  /Library/WebServer/Documents/sym/qwilm/public/workspace/masters/default.xsl

                

Now you can open the default.xsl file and delete the “navigation” template. You can also find the navigation.xsl file (if you have changed the name of the “Main Menu” utility to “Navigation”, otherwise, the file name will be main-menu.xsl. You can find this file in the /workspace/utilities/ directory. On my Mac, the file is here:

                  /Library/WebServer/Documents/sym/qwilm/public/workspace/utilities/navigation.xsl

                

Adjusting the home page link

One thing that you might consider a problem is that the Home page link is also given a handle of “home” so that the URL is:

                  http://sym.qwilm.site/home/

                

If you would rather that the link to the home page be the root of your site, you will need to test for another condition. For this, we can use the page “type” attribute to filter out the Home page and apply a different template for the output of this page link. As with any XML document, though, it is important to write well-formed code to keep all elements closed, either with opening and closing tags or with self-closing tags. This prevents us from being able to wrap the conditional elements only around the opening <li> tag and adding the “current” class attribute only when the conditions are right. The conditional element must contain the entire list item element from opening tag <li> to closing tag </li>. While it is rather verbose, it does afford us the functionality of dynamically assigning the “current” class to the current page menu item. Two additional conditions must be tested which apply a different template, omitting the handle from the link URL, when the type attribute is also equal to the string value of ‘index’:

                  <xsl:template name="main-menu">
    <ul>
        <xsl:for-each select="data/navigation/page">
            <xsl:choose>
                <xsl:when test="@handle=$current-page and @type='index'">
                    <li class="current">
                        <a href="{$root}/">
                            <xsl:value-of select="title"/>
                        </a>
                    </li>
                </xsl:when>
                <xsl:when test="@handle!=$current-page and @type='index'">
                    <li>
                        <a href="{$root}/">
                            <xsl:value-of select="title"/>
                        </a>
                    </li>
                </xsl:when>
                <xsl:when test="@handle=$current-page">
                    <li class="current">
                        <a href="{$root}/{@handle}/">
                            <xsl:value-of select="title"/>
                        </a>
                    </li>
                </xsl:when>
                <xsl:otherwise>
                    <li>
                        <a href="{$root}/{@handle}/">
                            <xsl:value-of select="title"/>
                        </a>
                    </li>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </ul>
</xsl:template>

                

Modifying files with a text editor

While each file must be created in Symphony so that metadata can be stored in the database relating to the Data Sources and/or Events that have been associated with a Master template, it is possible to modify the XSL file in a text editor. This can speed up development as you can have multiple XSL files open in your text editor while you quickly test the effect of modifications to your templates on the front end of your site in your web browser. Using an FTP application that can open files from a remote server to modify them locally in a text editor can be much quicker than navigating back and forth between pages in Symphony and you may benefit from the ability to undo and redo changes to your XSL templates. The same is true for Masters, Pages and Utilities, which all exist as XSL files on the server.

Since all the files you create in Symphony are stored in the workspace directory, it is possible to swap out the workspace with another workspace and completely change the behaviour and style of the site. However, to do this with an existing install of Symphony, it is necessary to have exactly the same database structure as before. Otherwise, it would be best to start with a fresh Symphony install to switch to a new theme. Since the latest version of Symphony allows for an amazing degree of back-end customization, differences in database structures prevent the ability to switch to different themes on the fly. For this reason, it would make sense for the Symphony community to develop some standard frameworks for various types of websites to facilitate this sort of theme switching, without worrying that swapping out the workspace might break the site.

Next: Sections and Custom Fields

Now that we are starting to become familiar with creating Masters, Pages, Utilities and Data Sources, we should start to develop some content. Next, in Building a Symphony Theme: Part 4 we will create Sections and Custom Fields to manage our content. This is where things start to become really exciting: the degree to which you can customize the Symphony Admin pages as well as the structure and functionality of your data.