Deploying and activating SharePoint 2013 themes using Visual Studio

Update: Times have changed since I wrote this article. The Office 365 Development Patterns and Practices (formerly known as AMS) now includes an excellent and more advanced example of theme management (including uploading themes): https://github.com/OfficeDev/PnP

I won’t deny it… I never was a big fan of theming SharePoint sites. In MOSS this was implemented absolutely awful and the SharePoint 2010 *slash* PowerPoint approach didn’t do it for me either. Glad to see both annoyances are gone now. Let’s take a look at how SharePoint 2013 changes the game and what we need to do to change its looks!

Themes in SharePoint 2013 consist of two things:

  • A theme, as in colorscheme
  • Optionally a fontscheme

Furthermore, a theme is part of what is called a “Composed Look”. These Composed Looks are essentially what is available to you when you click the “Change the look” under Site Settings.

SiteSettings1

Besides a color- and fontscheme the following items are part of a composed look:

  • A master page, this can also be a custom master page
  • Optionally a background image

The solution

Things I like to have changed in my custom look:

  1. Some UI colors for specific elements, in this case the SuiteBar at the very top
  2. Some of the fonts used
  3. Add a custom background image

In the end, it should look like this:

Result

I like the default look, but also want to include a background image. This default look is called the Office Look and it doesn’t use any specific font. For fonts, I favour the one used for “Sea Monster”. BTW, don’t you love that theme’s name? If you want to take a look at all the different OOTB themes, take a peek under “Change the look” in your site settings.

Most of these tasks can be done through the UI by uploading the artifacts manually. In this case (and almost any case) I like to use Visual Studio to ensure the correct deployment of these files. Theming, at least for me, is usually done for on premise or dedicated SharePoint solutions, so I don’t mind creating Farm solutions for this task.

Since the schema is pretty important, it is best to start with some of the OOTB parts:

  1. First we copy the color pallette used by the Office Look, since we like most of this OOTB theme
  2. Then we copy the fonts used by Sea Monster
  3. And finally grab your custom background logo. Make sure you keep the size of this file under 150KB!

You can download the color palette and fontscheme from the links in the “Composed Looks” settings section.

ComposedLook.1png

To set this up using Visual Studio 2012, we create a new Solution and make it a Farm Solution.

FarmSolution

Next, we add a mapped “Images” folder for our background image.

Then, we add a module (or two if you are including a custom master page) to deploy our Theme and Fontscheme. Add the artifacts and rename them appropiately (companylook-palette001.spcolor and companylook-fontscheme001.font in my case)
Modify the elements.xml so we deploy to the correct catalogs. Don’t forget to add GhostableInLibrary attribute!

This table lists the possible deployment options for our artifacts:

Master Pages <Module Name=”[Module Name]” Url=”_catalogs/masterpage”>
<File Path=”[Module Name][Master Page Name].master” Url=”[Master Page Name].master” Type=”GhostableInLibrary” />
</Module>
Themes <Module Name=”[Module Name]” Url=”_catalogs/theme/15″
<File Path=”[Module Name][Theme Name].spcolor” Url=”[Theme Name].spcolor” Type=”GhostableInLibrary” />
</Module>
Fontscheme <Module Name=”[Module Name]” Url=”_catalogs/theme/15″
<File Path=”[Module Name][Theme Name].spfont” Url=”[Theme Name].spfont” Type=”GhostableInLibrary” />
</Module>

Note: The attribute Type=”GhostableInLibrary” indicates that the item is added to the content database. The Url attribute of the module specifies where to store the file in the content database.

This is what your solution structure should look like right now:

Structure

To create a “Composed Look” we actually need to insert a listitem in the “Composed Looks” list. To do this we use a Feature Receiver that adds the list item with the correct field values:

Add a feature receiver to our solution’s feature. Set the scope to “Web”

Then add the following code to insert our custom list item:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            var web = properties.Feature.Parent as SPWeb;
            var list = web.GetList(string.Format(&amp;quot;{0}/_catalogs/design&amp;quot;,web.ServerRelativeUrl));
            var item = list.AddItem();

            item[&amp;quot;Title&amp;quot;] = &amp;quot;CompanyLook&amp;quot;;
            item[&amp;quot;Name&amp;quot;] = &amp;quot;CompanyLook&amp;quot;;
            item[&amp;quot;DisplayOrder&amp;quot;] = 1;

            var masterPageUrl = new SPFieldUrlValue();
            masterPageUrl.Url = masterPageUrl.Description = &amp;quot;/sites/dev/_catalogs/masterpage/seattle.master&amp;quot;;
            item[&amp;quot;MasterPageUrl&amp;quot;] = masterPageUrl;

            var themeUrl = new SPFieldUrlValue();
            themeUrl.Url = themeUrl.Description = &amp;quot;/sites/dev/_catalogs/theme/15/companylook-palette001.spcolor&amp;quot;;
            item[&amp;quot;ThemeUrl&amp;quot;] = themeUrl;

            var fontSchemeUrl = new SPFieldUrlValue();
            fontSchemeUrl.Url = fontSchemeUrl.Description = &amp;quot;/sites/dev/_catalogs/theme/15/companylook-fontscheme001.spfont&amp;quot;;
            item[&amp;quot;FontSchemeUrl&amp;quot;] = fontSchemeUrl;

            var imageUrl = new SPFieldUrlValue();
            imageUrl.Url = imageUrl.Description = &amp;quot;/_layouts/15/images/CompanyLook/Background.png&amp;quot;;
            item[&amp;quot;ImageUrl&amp;quot;] = imageUrl;

            item.Update();
        }

Remember to set the DisplayOrder, otherwise you will get the default value of 100 and your look will be hidden behind the “Grey” look.

This takes care of the deployment of our custom theme. Site owners can now activate it using the site settings, but you can also do it using code behind with another feature receiver.

Add a feature and feature receiver to our solution. Again, set the scope to “Web”. Add the following code to activate the custom look:

 public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            var web = properties.Feature.Parent as SPWeb;
            var list = web.GetList(string.Format(&amp;quot;{0}/_catalogs/design&amp;quot;, web.ServerRelativeUrl));

            SPQuery query = new SPQuery();
            query.ViewFields = &amp;quot;&amp;lt;FieldRef Name='ThemeUrl' /&amp;gt;&amp;lt;FieldRef Name='ImageUrl' /&amp;gt;&amp;lt;FieldRef Name='FontSchemeUrl' /&amp;gt;&amp;quot;;
            query.Query = &amp;quot;&amp;lt;Where&amp;gt;&amp;lt;Eq&amp;gt;&amp;lt;FieldRef Name='Name' /&amp;gt;&amp;lt;Value Type='Text'&amp;gt;CompanyLook&amp;lt;/Value&amp;gt;&amp;lt;/Eq&amp;gt;&amp;lt;/Where&amp;gt;&amp;quot;;

            SPListItemCollection listItems = list.GetItems(query);

            if (listItems.Count &amp;gt;= 1)
            {
                var theme = new SPFieldUrlValue(listItems[0][&amp;quot;ThemeUrl&amp;quot;].ToString());
                var font = new SPFieldUrlValue(listItems[0][&amp;quot;FontSchemeUrl&amp;quot;].ToString());
                var image = new SPFieldUrlValue(listItems[0][&amp;quot;ImageUrl&amp;quot;].ToString());

                if (theme != null &amp;amp;&amp;amp; font != null &amp;amp;&amp;amp; image != null)
                {
                    // In production code, make sure the files exist before applying the theme!
                    var themeUrl = (new Uri(theme.Url)).AbsolutePath;
                    var fontSchemeUrl = (new Uri(font.Url)).AbsolutePath;
                    var imageUrl = (new Uri(image.Url)).AbsolutePath;

                    web.ApplyTheme(themeUrl, fontSchemeUrl, imageUrl, true);
                }
            }
        }

That’s it! You can download the complete Visual Studio 2012 solution here.

Update: I changed the Visual Studio solution a bit to a more robust version.  You can find it here: Blog.Examples.CompanyLookTheme.zip

Advertisements

20 comments

  • when i tried to deploy your code in following site like “http://vmdev-sp13:34636/” item not appear in composed list

    • Zahid,

      thanks for the comment. Since it is not production code, you might want to take a look at the lines containing the relative urls. In this case “/sites/dev”. I will update the post and add a more robust VS2012 solution, just in case.

    • Zahid,

      you can find the link to the modified solution at the end of the article.

      /Y.

  • i used SP2012. when i deploy, it stop in active features and show error message : Group cannot be found. Could you give me some advices or any suggest, plz 😕

    • Griever,

      Assuming VS2012, do you deploy using Visual Studio or manually by uploading the WSP? And did you use the updated version (Blog.Examples.CompanyLookTheme.zip)?

      /Y.

  • Hi Yuriburger,

    Looking at the code for applying the composed look, if the composed look doesn’t have ImageUrl specified (like ‘Office’ which is out of the box) the method will through a Null Reference Exception.

    Besides, as per MSDN reference the urls passed to ApplyTheme method should be server relative urls as opposed to absolute path.

    • Hi Shahram,

      thanks for your reply. You are correct about the absolute vs. relative paths. It was already corrected in the Updated Visual Studio solution, I forgot to update the article itself.

      /Y.

  • Hi Yuri, what is the value in creating a composed look item in the design catalog list when you can’t apply it by name but have to copy the attributes out to supply them to the web.ApplyTheme() method, and that doesn’t account for setting the master page? Your code does not set the master page for the web, although through the site settings GUI a composed look combines the theme and master page as a single package.

  • Juha Metsäkallas

    The activating code gives you in SP2013+VS2012 a message saying SPWeb.ApplyTheme method is obsolete. Morever there seems to be a lot of code compared to official MS code at http://msdn.microsoft.com/en-us/library/jj927175.aspx#section1

    • Hi Juha,

      This code also takes into account, that you want to add a list entry for the Composed Look catalog (simplifying selecting the theme after you switch to a different theme). I will need to revisit the code and avoid the obsolete method, thanks for notifying!

      /Y.

  • Hello Yuri,

    beautiful code you have there. But in “Blog.Examples.CompanyLookTheme.zip” somehow I missing the code in the “Deployment” section, so the theme is selected as “current theme” on all sides. Can you resubmit it?

    Thank you.

    With best regards
    Hendrik

  • Nice idea – but does not work. Tried quite a few variations, got your latest code, etc. Any news or updates?

    • Hi John, sorry to hear it doesn’t work. Although I wouldn’t mind taking a look at your findings, times have changed a bit since I wrote the article. There is now an excellent sample included with the Office 365 Development Patterns and Practices (formerly known as App Model Samples). The Theme sample is part of this repo: https://github.com/OfficeDev/PnP/tree/master/Samples/Branding.DeployCustomThemeWeb

      • Hi Yuri thanks for the speedy reply. We are developing on premises and I am currently working on a development box that is set up in – I guess – a somewhat typical architecture as an SP server. I am using VS 2013, creating new SP project, etc. I RDP into that machine and work away. I actually have your solution loaded into my desktop’s VS for reference and have made sure what I have is the same in general – paths are obviously relevant to our environment. So….If you wish me to continue with this narrative I will – or we can switch to an email exchange so as to not clog-yer-blog…so to speak. I will add one more reply shortly with a little more specifics on my actual findings from attempts to use your technique. Thx.

  • So…it seems that the first feature – which in your solution is called CompanyLookInstallation and in mine is called TH_Brand_Install (I work for Trihydro Corporation in Laramie, Wyoming, USA – hence the TH) – deployment and activation work but as there is no ‘applytheme’ for this feature it seems that since I can now see it in the list of composed looks, and in the list of Site Features, that is done. However there is an error in deployment in the second feature – the one with the ApplyTheme – because the var web is coming up null right away…I debugged it and found that out. So it never hits the ApplyTheme. I would like to be able to add my own masterpage to the first feature and then have the second feature work correctly. seems the scope for that feature being Site means it can’t retrieve from properties.Feature.parent as SPWeb?

    • Ok, let me set this up in a VM and see where the code fails. Shall we continue using email as you suggested? yurib[at]delta-n[dot]nl

      • send test email – let me know when you get it. I changed how the SPWeb object was fetched and it works. I can send code when you wish.

  • Is the pattern being used in the .feature strict/consistent, whereby the Feature that you call CompanyLookInstallation has Scope = Web, and the Module references are all under Items-In-the-solution and NOT under Items in the feature, and for the one you call CompanyLookDeployment has Scope=Site, and the opposite of above so they are all under Items in the feature? And thus, to add my MasterPage I should do exactly that with my MasterPage module?

    Thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s