I recently had a requirement to update the branding on an existing Windows SharePoint Services (WSS version 3.0) site. I needed to update the theme, along with the master page. An additional requirement is that my client likes to have all changes bundled up in SharePoint solutions. This makes it much easier to move code from dev to test to prod and more importantly, makes it easier to undo code migrations if any issues would arise (I agree with this approach). Updating the theme was easy enough. I created a new theme, along with a two new features. The first feature, scoped at the farm level, deploys the theme, adding it to the spthemes.xml file (in the 12 hive –> \Template\layouts\1033 folder). Here’s the method that I call from the feature activated event: private static void AddThemeToSpThemes(string id, string name, string description,
string thumbnail, string preview, SPFeatureReceiverProperties properties)
{
XmlDocument spThemes = new XmlDocument();
//use GetGenericSetupPath to find the 12 hive folder
string spThemesPath = SPUtility.GetGenericSetupPath(@"TEMPLATE\LAYOUTS\1033\spThemes.xml");
//load the spthemes file into our xmldocument, since it is just xml
spThemes.Load(spThemesPath);
XmlNode root = spThemes.DocumentElement;
//search the themes file to see if our theme is already added
bool found = false;
foreach (XmlNode node in root.ChildNodes)
{
foreach (XmlNode prop in node.ChildNodes)
{
if (prop.Name.Equals("TemplateID"))
{
if (prop.InnerText.Equals(id))
{
found = true;
break;
}
}
}
if (found)
{
break;
}
}
if (!found) //theme not found, so add it
{
//This is what we need to add:
// <Templates>
// <TemplateID>ThemeName</TemplateID>
// <DisplayName>Theme Display Name</DisplayName>
// <Description>My theme description</Description>
// <Thumbnail>images/mythemethumb.gif</Thumbnail>
// <Preview>images/mythemepreview.gif</Preview>
// </Templates>
StringBuilder sb = new StringBuilder();
sb.Append("<Templates><TemplateID>");
sb.Append(id);
sb.Append("</TemplateID><DisplayName>");
sb.Append(name);
sb.Append("</DisplayName><Description>");
sb.Append(description);
sb.Append("</Description><Thumbnail>");
sb.Append(thumbnail);
sb.Append("</Thumbnail><Preview>");
sb.Append(preview);
sb.Append("</Preview></Templates>");
root.CreateNavigator().AppendChild(sb.ToString());
spThemes.Save(spThemesPath);
}
}
Just as important, is the code that removes the theme when the feature is deactivated:
private static void RemoveThemeFromSpThemes(string id)
{
XmlDocument spThemes = new XmlDocument();
string spThemesPath = HostingEnvironment.MapPath("/_layouts/") + @"1033\spThemes.xml";
spThemes.Load(spThemesPath);
XmlNode root = spThemes.DocumentElement;
foreach (XmlNode node in root.ChildNodes)
{
foreach (XmlNode prop in node.ChildNodes)
{
if (prop.Name.Equals("TemplateID"))
{
if (prop.InnerText.Equals(id))
{
root.RemoveChild(node);
spThemes.Save(spThemesPath);
break;
}
}
}
}
}
So, that takes care of deploying the theme. In order to apply the theme to the web, my activate feature method looks like this:
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
using (SPWeb curweb = (SPWeb)properties.Feature.Parent)
{
curweb.ApplyTheme("myThemeName");
curweb.Update();
}
}
Deactivating is just as simple:
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
using (SPWeb curweb = (SPWeb)properties.Feature.Parent)
{
curweb.ApplyTheme("none");
curweb.Update();
}
}
Ok, that’s the code necessary to deploy, apply, un-apply, and retract the theme. Also, the solution (WSP file) contains the actual theme files.
SO, next is the master page, which I’ll cover in my next blog post.