Hello budding Symphonists, and welcome to the long-delayed part 3 of our tutorial series! In the last episode, we did some relatively mundane work prepping the structure of our portfolio website. Part 3′s where we crank up the fun and dive into Pages, Data Sources, XML, XSLT, and maybe some other wicked sweet acronyms. Our goal is to end up with a site that looks like this:

Before I move on to the action, just wanted to mention that several versions of Symphony have been released since I (long ago) began this series. As of this writing, the current version is 2.2. It’s fantastic, go get it.
Getting Started with Pages and Templates
OK, let’s begin by getting our rough template in place. If you’ll recall, back in part 1, we preloaded an XSLT Utility called html5.xsl (in case you forgot, it’s here.) This is a great master template that gives us a standard HTML5 layout marked up in XSLT and ready for use in Symphony.
So how do you use this thing? Take a look at our Symphony pages by going to Blueprints > Pages.

P-P-P-Pages
As you can see, we already have several pages, .xsl templates, and corresponding URLs in our new site. These came with the default workspace. To be clear, pages in Symphony are not really “pages” in the traditional sense. Says the documentation, “pages are not simply containers for static content and there is not a one-to-one relationship between a page and the content accessible via that page. A single Symphony page can power an entire browsing interface.”
Not surprisingly, pages are the bread and butter of your site, tying together your content, templates, and user interface elements. (Don’t worry, this will make more sense in a minute.)
Anyway, each page has its own .xsl template file. This allows you to customize how that page’s content is displayed in a browser. Take a look at our home page template by selecting the home.xsl link.

Home is where the XSLT is
Not much to it, eh? Almost all of this page’s layout and content is arranged and formatted by other XSLT utilities that are imported to this template; the relevant imported utilities are highlighted in blue in the right column. In that list, click on master.xsl.

The Template Master
Aha! This is the primary site design template, which can be imported into all of our main pages. This template provides the standard elements of a site design: header, nav, etc. (But to our horror, this master.xsl is old-school XHTML, which was excellent about one year ago but is suddenly the laughingstock of fashionable web designers.)
Let’s hang on to this master.xsl for now, and switch our home page to our preferred template, html5.xsl. Go back to the home.xsl template and change this line:
<xsl:import href="../utilities/master.xsl"/>
<xsl:import href="../utilities/html5.xsl"/>
Let’s also get rid of some bits we don’t need. We’re not going to use the Notes or Comments functions from the default installation, so remove these lines:
<xsl:import href="../utilities/get-notes.xsl"/>
<xsl:import href="../utilities/get-comments.xsl"/>
<xsl:apply-templates select="notes"/>
Save your changes. For our last bit of work in this area, click on the html5.xsl utility and peruse its code. Let’s start over with styling by modifying our stylesheet name:
<link rel="stylesheet" media="screen" href="{$workspace}/css/styles.css" />
change styles.css to “demostyles.css.” This file doesn’t exist yet, so we will initially have no CSS styles applied to our site.
OK, save the changes. Now to see what we’ve done:

1996 called and wants it website back.
Hmm, ugly. But we’re not done yet. Our next matter of business is to make sure all the content we want is available on the home page.
Data Sources
In Symphony, Data Sources are a method to select content from sections and make it available in pages. Remember, we defined several sections — Projects, Categories, Images, and Tweets — but only a fraction of this content is currently visible on our home page. Let’s fix that. Go to Blueprints > Components, and have a look at the Data Sources list.

A Fountain of Data
As usual, there are some pre-made Data Sources here, and we can reuse most of them. Since there is no Data Source for our Tweets, let’s make one. Select Create New.

Creating a Data Source For Some Homestyle Tweetin's
this can look a little intimidating at first, but it’s actually not so bad. Start out by naming this Data Source “Tweets” and select the Tweets section from the Source menu.
The next step to consider is whether you want to Filter your Tweets by some criteria. For now we’ll leave this alone, but one example I use on my site is to hide any @-replies to specific people, using this filter: not-regexp:^@. Note: not-regexp is new in Symphony 2.2.
Next, we’ll have to decide how we want to Sort and Limit our Tweets. I would like them to be in descending date order (newest at the top) and I don’t want to see more than three Tweets on the home page. So, change Sort By to Date and change “Show a maximum of 20 results per page” to 3.
In the Included Elements select list, choose permalink, tweet, and date. These are the pieces of a Tweet that will be available to your page.
We’re done for now — select Create Data Source.
Wait, we’re not done! We need to instruct our home page that this new Data Source is available. Go back to Blueprints > Pages, and click on the Home link in the Title column. This brings up the Page Settings screen for the home page.

Setting Page Settings
Command or Control -click on the Tweets Data Source to make sure it’s selected, and then Save Changes. Now let’s have another look at our home page.

Tweet?
As you can see, our Tweets are all here. What’s that? They’re not? Here’s why: the home page now has access to our Tweets data, but we haven’t added any Tweet formatting to our front-end templates yet. Don’t believe me? Click the Debug link or append ?debug=xml to the end of the URL, and begin to understand the glory that is Symphony.

Oh, the sweet sweet Tweet glory.
Now you’re seeing the output of all the Data Sources enabled for this page, rendered as XML. We’re free to use XSLT to transform this into whatever format we want (in this case it’s HTML, but it doesn’t have to be.) So let’s do that. There are many ways to approach this, so I’ll give you one example, but you can try other variations too.
A Spot of XSLT
Go to Blueprints > Components and in the Utilities section, select Create New. We’re going to name this utility get-tweets.xsl. Paste in the following code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="../utilities/talinkahashifyer.xsl"/>
<xsl:template name="get-tweets" match="tweets">
<ul>
<xsl:apply-templates select="entry"/>
</ul>
</xsl:template>
<xsl:template match="tweets/entry">
<li>
<xsl:call-template name="linkahashify">
<xsl:with-param name="tweet" select="tweet" />
</xsl:call-template>
</li>
</xsl:template>
</xsl:stylesheet>
(I’ll step through this briefly, but be sure to check out the metric ton of information about XSLT out there.)
Our Tweets XML looks like this:
<tweets>
<section id="7" handle="tweets">Tweets</section>
<entry id="19">
<permalink handle="19927170746">19927170746</permalink>
<tweet>Trusty 6-year-old WRT54G router died in a fit of buzzy, maniacal rage. Suggestions for a new model? (N, preferably.)</tweet>
<date time="12:41" weekday="5">2010-07-30</date>
</entry>
<entry id="20">
<permalink handle="19876287923">19876287923</permalink>
<tweet>Do you like to write? Are you crazy about #symphonycms? Or just crazy? Join me on the Documentation Working Group! http://bit.ly/bhVE6z</tweet>
<date time="21:41" weekday="4">2010-07-29</date>
</entry>
<entry id="21">
<permalink handle="19843470091">19843470091</permalink>
<tweet>@nicksergeant given how long it took to get HTML5 and CSS3 off the ground, maybe it will happen by the time we retire :)</tweet>
<date time="12:46" weekday="4">2010-07-29</date>
</entry>
</tweets>
So here’s how the XSLT works:
<xsl:import href="../utilities/talinkahashifyer.xsl"/>
Imports the “talinkahashifyer” utility we downloaded from the Symphony site — this auto-formats the body of our tweets so things like links and @replies work.
<xsl:template name="get-tweets" match="tweets">
<ul>
<xsl:apply-templates select="entry"/>
</ul>
</xsl:template>
This selects the <tweets> parent element from our XML, and applies any relevant templates for the <entry> child elements. The output is contained in an unordered list (ul) tag.
<xsl:template match="tweets/entry">
<li>
<xsl:call-template name="linkahashify">
<xsl:with-param name="tweet" select="tweet" />
</xsl:call-template>
</li>
</xsl:template>
This matches all <entry> elements contained in the <tweets> element, and formats them by calling the linkahashify template (the actual tweet content is sent as a parameter to that template.) This output will be contained in a list (li) element.
For our example, the end result will be an unordered list of three tweets, organized in descending date order, and formatted appropriately:

This solution is admittedly somewhat abstract, but it’s good to familiarize yourself with <xsl:apply-templates> and <xsl:call-template>, as they are used heavily. Here’s a more straightforward way to do this with <xsl:for-each>, which might be more obvious for XSLT newbies who are familiar with other template languages:
<xsl:template match="tweets">
<ul>
<xsl:for-each select="entry">
<li>
<xsl:call-template name="linkahashify">
<xsl:with-param name="tweet" select="tweet" />
</xsl:call-template>
</li>
</xsl:for-each>
</ul>
</xsl:template>
Now that we have the get-tweets.xsl utility set up, let’s adjust our home page template to use it. Go to Blueprints > Pages and click on the home.xsl link.
We need to do two things: import get-tweets.xsl, and apply the tweets template to the content for this page. The complete home.xsl is below.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="../utilities/html5.xsl"/>
<xsl:import href="../utilities/get-article.xsl"/>
<xsl:import href="../utilities/get-tweets.xsl"/>
<xsl:template match="data">
<xsl:apply-templates select="homepage-articles/entry"/>
<xsl:apply-templates select="tweets"/>
</xsl:template>
</xsl:stylesheet>
Woo, now let’s check the page one more time.

Tweets are go
For our last content trick, we need to display some thumbnail images for each project. Before we do that, let’s clean up and tweak our setup a bit.
First, go to the Articles page and rename it Projects. We want this page to be available to the navigation, so remove the hidden page type.

Projectifying
Next, delete Comments, Notes, and Drafts stuff from the Blueprints > Components and Blueprints > Sections areas.

Clean as a whistle
For my last bit of cleanup, I’m going to replace all instances of the word ‘article’ with the word ‘project’ in the remaining XSLT page templates, utilities, and data sources. This is mostly for looks, you could skip this. Note that there are several ways to go about this sort of thing, you can either edit the files via the Symphony interface (slower) or operate on them as files in $site-root/workspace (faster).
Dealing with Images
Now that things are tidy, let’s work on getting images on the home page. There are three items that need to be tweaked: the Project Images data source, and some XSLT utilities.
We only want to display thumbnails on the home page and projects page, so in the Project Images data source, add a Filter based on the Image Type, and set it to Thumbnail.

Bring out your thumbnails
Next, we’ll make some minor changes to the get-images.xsl template. We’re mainly removing the default JIT resizing code, because our thumbnails are already the size we want. Full template code here:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="get-images">
<xsl:param name="entry-id"/>
<xsl:if test="/data/project-images/entry[project/item/@id = $entry-id]">
<xsl:apply-templates select="/data/project-images/entry[project/item/@id = $entry-id]"/>
</xsl:if>
</xsl:template>
<xsl:template match="project-images/entry">
<a href="{$workspace}/uploads/{image/filename}">
<xsl:if test="position() mod 3 = 0">
<xsl:attribute name="class">last-column</xsl:attribute>
</xsl:if>
<img title="{description}">
<xsl:attribute name="src">
<xsl:value-of select="$root"/>
<xsl:text>/workspace/uploads/</xsl:text>
<xsl:value-of select="image/filename"/>
</xsl:attribute>
</img>
</a>
</xsl:template>
</xsl:stylesheet>
Finally, we’ll update the homepage-projects/entry portion of the get-project.xsl template. This is just a matter of simplifying what came with the default workspace.
<xsl:template match="homepage-projects/entry">
<div class="entry">
<xsl:call-template name="get-images">
<xsl:with-param name="entry-id" select="@id"/>
</xsl:call-template>
<p class="imgcaption">
<a href="{$root}/projects/{title/@handle}/"><xsl:value-of select="title"/></a>
<xsl:if test="$is-logged-in = 'true'">
<xsl:text> — </xsl:text>
<a class="edit" href="{$root}/symphony/publish/{../section/@handle}/edit/{@id}/">Edit</a>
</xsl:if>
</p>
</div>
</xsl:template>
this code simply wraps each thumbnail in a <div>, with its title displayed as a caption below in a <p> and a handy Edit link if you’re logged into Symphony as an editor.
Phew, that was a lot of work, but our home page is finally where we want it:

Portfolio home page in the raw
We’re close to the finish line now! I’m going to end this series with a short Part 4, in which I’ll add the About and Projects pages, and some styles to pretty everything up. You will also be able to download the sample site as an ensemble.
P.S. I won’t take so long for the Part 4, I promise
Jonas, this couldn’t be more welcome than now as I’m trying to get my head around Symphony! I love Symphony. It gets you there after going thru the usual cmses like WP, TXP, EE etc. But not before. I love the minimalistic approach and the granular control you get with Symphony. Great post! Thank you so much!
Glad it helped, man! Good luck with your project.
Big help! Got me started with sympohny, thanks.
Hi nice Tutorial …
Can you post us all modified files as a download ?
thx
Hi quma, the entire site will be available as an ensemble in the near future, once I get some time to package it up. Stay tuned!
Jonas, Nice tutorial, What about using a static xml doc as a data source? Can you explain how to accomplish it?
any idea when part4 is ready ?