Using Feature to apply themes in SharePoint 2013 Preview

In my previous post I wrote about applying custom theme to SharePoint 2013 site using new theming engine. I also mentioned that one approach for implementing this functionality could be to encapsulate this code in Feature receiver. In this post, I will demonstrate and explain this approach for applying custom theme to SPWeb. Our custom theming Feature will

  1. On Feature Activated create and apply new theme to the existing web, while preserving information about current theme

  2. On Feature Deactivating restore preserved information about previous theme and apply it to the target web.

This all seems to be quite straightforward and clear, very similar to this process in previous SharePoint versions. One step that is not so clear to implement is How to preserve information about current theme? in order to be able to successfully restore and apply that theme later. For that, we need to know answer to the following:

Where are theme files in SP2013?

All themes in SharePoint 2013, regardless of the fact if they are built-in or custom themes, store information about themes in file theme.sptheme . That .sptheme is XML file, it can contain information about applied color palette, font scheme, master page and background and it is stored in appropriate folder for particular theme:

  • For builtin  themes, each theme has its corresponding folder inside /_themes folder

  • For custom themes, when the theme is applied, custom theme folder (with unique name) is created in folder Themed inside theme gallery, for example /_catalogs/theme/Themed/60F3749C

This folder contains all files which are relevant to particular theme – customized palettes, font schemes, background images etc. Information about path of this folder for currently applied theme is stored in property ThemedCssFolderUrl of target SPWeb.

Show me the code!

Here is code which performs all functionality that we need. Complete code for both Feature receivers is shown at the end of this blog post (so that you can copy it in its entirety):

In Feature Activated event receiver, we

  • Create new custom theme based on SPCOLOR file which exists in theme library, SPFile spColorFile = targetWeb.GetFile(targetWeb.ServerRelativeUrl + "/_catalogs/theme/15/Palette002.SPCOLOR"); SPTheme spTheme = SPTheme.Open("ProgrammedTheme", spColorFile);

  • Preserve information about current theme in SPWeb property bag (make sure to call Update() on both SPWeb and SPWeb.Properties after this)  targetWeb.Properties["OldSpThemeFolder"] = targetWeb.ThemedCssFolderUrl;

  • Apply new custom theme to our target web. spTheme.ApplyTo(targetWeb, true);

In Feature Deactivating event receiver, we need to

  • Restore information about previous theme folder from SPWeb property bag string spThemeFolder = targetWeb.Properties["OldSpThemeFolder"].ToString();

  • Open theme configuration file and create SPTheme object  SPFile spThemeFile = targetWeb.GetFile(spThemeFolder + "/theme.sptheme"); SPTheme themeToRevert = SPTheme.OpenFromXml(spThemeFile);

  • Apply Theme to our target web themeToRevert.ApplyTo(targetWeb, true);

During process of reverting to previous theme, we are using slightly different approach – previous theme already has existing Theme configuration file, so we are not creating new theme but instead we are opening existing theme file in method OpenFromXml from SPTheme class.

Here is a complete code sample of both Feature receivers.

public override void FeatureActivated(SPFeatureReceiverProperties properties) {     SPWeb targetWeb = properties.Feature.Parent as SPWeb;                SPFile spColorFile = targetWeb.GetFile(targetWeb.ServerRelativeUrl + "/_catalogs/theme/15/Palette002.SPCOLOR");               targetWeb.Properties["OldSpThemeFolder"] = targetWeb.ThemedCssFolderUrl;     targetWeb.Properties.Update();     targetWeb.Update();                SPTheme spTheme = SPTheme.Open("ProgrammedTheme", spColorFile);               spTheme.ApplyTo(targetWeb, true);            }

public override void FeatureDeactivating(SPFeatureReceiverProperties properties) {     SPWeb targetWeb = properties.Feature.Parent as SPWeb;     if (targetWeb.Properties["OldSpThemeFolder"] != null)     {         string spThemeFolder = targetWeb.Properties["OldSpThemeFolder"].ToString();         SPFile spThemeFile = targetWeb.GetFile(spThemeFolder + "/theme.sptheme");         if (spThemeFile != null)         {             SPTheme themeToRevert = SPTheme.OpenFromXml(spThemeFile);             themeToRevert.ApplyTo(targetWeb, true);         }     }

Until next time – You can comment about this post below, or using twitter and facebook.

Dragan