The Dreamweaver integration for Modular Templating enables you to rapidly upload HTML designs into SDL Tridion and publish them onto your website. However there are some common stumbling blocks related to how 2nd level dependencies are managed (for example the relationship between CSS and images), and the structure of the published files on your website. This article outlines these issues and illustrates a simple approach to overcome them.
Easily Publish Website Design
Article Sections
The Get Design Elements Template Building Block described in this article can be downloaded here .
- Easily Publish Website Design (1) - The basics
- Easily Publish Website Design (2) - An example
- Easily Publish Website Design (3) - How to publish the whole design
- Easily Publish Website Design (4) - Limitations and Further Ideas
How to do preserve structure and publish all design assets with a .NET TBB
The assumptions that we make are:
- That we decide to publish all multimedia components that are uploaded into the CMS as part of the design and not worry about the 2nd or 3rd level dependencies between items.
- The we have created structure groups (SGs) that mirror the structure of the HTML prototype (they start from a sub structure group, provided the HTML prototype will also work in a sub folder of the website) - in our example this means we create css and img SGs
Then it is a case of creating a .NET TBB to do the processing:
First we implement the Transform method. This will:
- Calculate the root SG to publish into (we assume here it is relative to the current (master) page we are publishing, but you could make this constant, or add your own logic)
- Read the root folder from which to read the MM components from a parameter (use a default as fallback) - we assume this is passed in as a webdav url, relative to the root folder.
- Recursively add all binaries from this folder and its subfolders using a separate method AddBinariesFromFolder
Note that in the example shown, it is assumed that we are using a TemplateBase class such as can be found here, with helper methods for getting references to the current page etc.
private string _rootSGWebDavUrl;
public override void Transform(Engine engine, Package package)
{
this.Initialize(engine, package);
Page page = this.GetPage();
//Set the root SG based on the current page
_rootSGWebDavUrl = page.OrganizationalItem.WebDavUrl;
//Locate the root folder to find images
Folder folder = null;
string sysfolderuri = package.GetValue("SystemComponentFolderWebdavUrl");
if (sysfolderuri == null)
{
sysfolderuri = "/System/Designs/Page%20Designs";
}
sysfolderuri = this.GetPublication().RootFolder.WebDavUrl + sysfolderuri;
folder = engine.GetObject(sysfolderuri) as Folder;
if (folder==null)
{
throw new Exception(String.Format("System folder {0} does not exist", sysfolderuri));
}
//Recursively add binaries from the folder and its subfolders
AddBinariesFromFolder(_rootSGWebDavUrl, folder, "");
}
The separate method to add binaries from a folder will do the following:
- Get a reference to the corresponding structure group
- Loop through all binaries found in the folder and add them to the SG using a separate method AddBinary
public void AddBinariesFromFolder(string rootSGWebDavUrl, Folder folder, string path)
{
//Try to get a reference to the sub Structure Group based on the folder title
StructureGroup sg;
sg = m_Engine.GetObject(rootSGWebDavUrl + path) as StructureGroup;
if (sg == null)
{
throw new Exception(String.Format("Could not find Structure Group {0}. Please create this and republish", rootSGWebDavUrl + path));
}
//Loop through all components in the folder
foreach (KeyValuePair<TcmUri, string> item in GetOrganizationalItemContents(folder, ItemType.Component, false))
{
Component mmComp;
mmComp = m_Engine.GetObject(item.Key) as Component;
if (mmComp.ComponentType == ComponentType.Multimedia)
{
//if its a MM comp then add it to the package, and publish it
AddBinary(mmComp, sg);
}
}
//Loop through all subfolders to recurse
foreach (KeyValuePair<TcmUri, string> item in GetOrganizationalItemContents(folder, ItemType.Folder, false))
{
Folder subFolder = m_Engine.GetObject(item.Key) as Folder;
AddBinariesFromFolder(rootSGWebDavUrl, subFolder, path + "/" + subFolder.Title);
}
}
The separate method to add a binary to a Structure Group does the following:
- Check if the binary is already in the package - which will be the case for CSS, JS etc linked from the DWT.
- If it is not in the package, we add it
- If an item is in the package but it has a different tcm uri, we replace it with the current item (this is to avoid conflicts with 2 different binaries with the same filename)
- We ensure the item will be published to the correct SG by calling the TOM.NET AddBinary method with the appropriate parameters
- We write the path of the published item back into the package item (so the LinkResolver will update links to this item in our output to use the correct path)
public void AddBinary(Component mmComp, StructureGroup sg)
{
Item packageItem = null;
string filename = Utilities.GetFilename(mmComp.BinaryContent.Filename);
//Check if the binary is already in the package (for example, if the DWT already added it
packageItem = m_Package.GetByName(filename);
if (packageItem != null)
{
KeyValuePair<string, string> pair = new KeyValuePair<string, string>("TCMURI", mmComp.Id.ToString());
if (!packageItem.Properties.Contains(pair))
{
//its a different item so we should push our item in the package
packageItem = null;
}
}
//if its not in the package, add it
if (packageItem == null)
{
packageItem = m_Package.CreateMultimediaItem(mmComp.Id);
m_Package.PushItem(filename, packageItem);
}
//Publish the binary into the appropriate SG
using (Stream itemStream = packageItem.GetAsStream())
{
try
{
byte[] data = new byte[itemStream.Length];
itemStream.Read(data, 0, data.Length);
string publishedPath = m_Engine.AddBinary(mmComp.Id, null, sg.Id, data, filename);
packageItem.Properties[Item.ItemPropertyPublishedPath] = publishedPath;
}
finally
{
itemStream.Close();
}
}
}
We add this TBB into the modular template between the DWT and Default Finish Actions, and when we publish, we see that
1) The HTML prototype structure is preserved
2) All binaries are published, not just the ones directly referenced in the DWT
You will notice also that if you un-publish your page, it will remove the CSS and image files from the webserver file system, because using AddBinary means that on the Content Delivery side, the binary files are managed correctly when content is unpublished.
This solution is a great first step, some limitations and further ideas are discussed in the final section .