This is the first in a series of 3 posts describing how Building Blocks manage storing and publishing CSS files in Tridion. The series details:
- Storing and publishing CSS files
- Handling image references
- Minimising CSS files on publish
We're arrived at these processes as they support the way that we work - Specialist Front End Developers maintain the CSS and site furniture images and are then able to integrate them directly into Tridion without having any knowledge of Tridion templating once the pages have been setup. The techniques used also mean they do not have to change the way they reference images or make specific deployment changes to the files prior to saving them in Tridion.
The first task we need to take care of is how we store the CSS files and publish them.
Storing and publishing code files
There are a number of times we want to store and publish pages using Tridion that are not based on a designed templates. They are usually files containing code - and need to be published using a specific file extension. In this case it's a CSS file, however, it could be an XSL file to render a website navigation at runtime or a server side code file such as a ".cs" file. In all of these examples the file has been authored outside of Tridion, but needs to be stored and published by it.
We don't want to create a page or component template for each one, as there may be many, so we need another solution. There are a number of options that I've seen implemented:
1. Deploy files manually using existing release procedures.
Tridion is by-passed and files are manually deployed to the presentation servers.
This works, however, it means that the deployment of the files are completely detached from any Tridion authoring processes and associated workflows. Additionally in the example of CSS files we don't want to separate the deployment of the markup (delivered in Tridion templates) and the CSS styles.
2. Create components based on a "Code" schema
Most SDL Tridion implementations have a "code" schema - a schema containing a single multi-line text field where a snippet or full document of code can be entered.
A component is then created for each item of code and saved within the folder structure. Usually the component is then placed on a page with a component template that simply outputs the contents of the field like:
Component c = GetComponent();
ItemFields fields = new ItemFields(c.Content, c.Schema);
String output = GetStringValues("code", fields);
package.PushItem("Output", package.CreateStringItem(ContentType.Html, output));
The page template (PT) selected for the page, has a specific extension set (e.g. .css) and loops through each component presentation writing out the rendered output. We call these "generic" page templates with one created for each extension we want to publish, although they all use the same TBB inside. In this example the PT is named "z_Generic Page Template CSS". The "z_" ensures that all the generic PTs are grouped together at the bottom of the PT list.
// loop through each component presentation, render it and append to a string
foreach (cm.CommunicationManagement.ComponentPresentation cp in page.ComponentPresentations)
output += engine.RenderComponentPresentation(cp.Component.Id, cp.ComponentTemplate.Id);
Publishing the page then creates a file on the presentation server using the correct extension and containing the code snippet/document.
Although this works, it involves a number of manual steps, which are not familiar to application or front end developers with limited knowledge of Tridion. This means it doesn't scale well if a large number of code files need to be added (and updated regularly) in Tridion. It also increases the risk of the code base maintained outside of Tridion becoming out of sync with the code stored and published in the components.
3. Code stored in Multimedia Components saved via WebDav
This method is similar to the last, but removes the need for a Code schema, instead storing the code as individual multimedia components via webdav. Storing the code in MM components allows the files to be saved directly using WebDav (or through an automated deployment process as described on Zhaph’s TFS integration post). Application/Front End Developers then update their files directly into Tridion using a mapped WebDav path, without having to open the Tridion GUI.
This will save the CSS file as a multimedia component, using the default multimedia component schema. The MM component is then added onto a page using the same process as in method 2. The Component Template TBB code is slightly different to read the code from the file uploaded, rather than from a code field. e.g.
Component c = GetComponent();
// read css in mm component into a string
UTF8Encoding encoding = new UTF8Encoding();
byte binary = c.BinaryContent.GetByteArray();
string output = (binary != null) ? encoding.GetString(binary, 0, binary.Length) : string.Empty;
// push contents into the package
package.PushItem("Output", package.CreateStringItem(ContentType.Text, output));
The same "generic" page template as described in method 2 is used to publish the page to the presentation servers.
We could write a publishing script to automatically publish the multimedia components without having them added to a page, but I think it's better to use pages and some Event System code could be created to automatically create and configure the pages using the mm components if needs be.
There are a couple of things to note:
Ensure that a file type for the file you are saving is setup in Tridion and associated to the Default Multimedia Component Schema.
When saving files using Tridion webdav it doesn't like file extensions that have more than 3 characters. File types like ASCX can't be saved directly. in our case we us a Continuous Integration tool to save the files into webdav, so we perform a transformation to rename the extension before attempting a save using webdav. This has worked well for us so far.
So what's the best way of getting server side files onto the presentation servers? In my opinion Method 3 gives us the maximum flexibility and allows us to work closely with other developers' existing workflows. We also get the benefit or storing these files within Tridion to take advantage of the publishing process.
We now have the basic way of getting our CSS files onto the web servers. My next couple of blog posts will look at handling images references made in the CSS file as well as running the code through some additional Template Building Blocks when publishing to deliver some additional benefits.