27 January 2010

Custom Theme and Feature Stapling via WSP files

Looking to deploy a custom theme in a solution file? Here’s how to modify the SPThemes.xml file programmatically using Linq to XML. The only thing missing would be clean-up of sites using the theme upon uninstall.
http://blogs.msdn.com/ketaanhs/archive/2009/07/01/modifying-spthemes-xml-programmatically-to-deploy-new-themes-moss-2007-wss-3-0.aspx
Recently used this for a client along with feature stapling to deploy a custom theme and then force all newly created sites to use the theme. I used the WSPBuilder templates for VS2008 (I prefer these above the templates VsWSS).
Step 1: Create a WebApplication scoped feature to handle the FeatureStapling and create a SPFeatureReceiver for the feature to install the feature into the SPThemes file using the technique above.


<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Creator="Chris Quick, Tribridge"
         Description="Forces default Client branding for all sites"
         Hidden="false"
         Id="9DEE24AC-1FF9-4fb3-AC07-2A0D9D616D99"
         Scope="WebApplication"
         Title="Client Default Branding"
         Version="1.0.0.0"
         ReceiverAssembly="Client.SharePoint.Branding, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7622be71ccc3f186"
         ReceiverClass="Client.SharePoint.Branding.ClientThemeInstaller">
  <ElementManifests>
    <ElementManifest Location="elements.xml"/>
  </ElementManifests>
</Feature>

Step 2: Setup feature stapling in your ElementManifest file. Make sure the ID of the feature to staple is the ID of the feature that applies the branding (created next).

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <FeatureSiteTemplateAssociation Id="FA5FE9BA-8DCB-40c8-950B-517AC11FCC23" TemplateName="GLOBAL"/>
  <FeatureSiteTemplateAssociation Id="FA5FE9BA-8DCB-40c8-950B-517AC11FCC23" TemplateName="STS#1"/>
</Elements>

Step 3: Create another feature scoped to the Web that will have a feature receiver using a co-worker’s method of applying a theme.

<Feature xmlns="http://schemas.microsoft.com/sharepoint/"
         Creator="Chris Quick, Tribridge"
         Description="Applies Branding to New Sites for Client"
         Id="FA5FE9BA-8DCB-40c8-950B-517AC11FCC23"
         Hidden="False"
         Scope="Web"
         Title="Client Branding Receiver"
         Version="1.0.0.0"
         ReceiverAssembly="Client.SharePoint.Branding, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7622be71ccc3f186"
         ReceiverClass="Client.SharePoint.Branding.ClientBrandFeatureReceiver">
  
</Feature>


using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;

namespace Client.SharePoint.Branding
{
    class ClientBrandFeatureReceiver : SPFeatureReceiver
    {
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SPWeb currentWeb = (SPWeb)properties.Feature.Parent;
            currentWeb.AllowUnsafeUpdates = true;
            currentWeb.ApplyTheme("Client");
            currentWeb.SiteLogoUrl = "/_layouts/images/Client/Client-logo.gif";
            currentWeb.Update();
            currentWeb.AllowUnsafeUpdates = false;
            currentWeb.Dispose();
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            SPWeb currentWeb = (SPWeb)properties.Feature.Parent;
            currentWeb.AllowUnsafeUpdates = true;
            string theme = currentWeb.Theme;
            string logoUrl = currentWeb.SiteLogoUrl;
            currentWeb.ApplyTheme("none");
            currentWeb.SiteLogoUrl = "/_layouts/images/titlegraphic.gif";
            currentWeb.Update();
            currentWeb.AllowUnsafeUpdates = false;
            currentWeb.Dispose();
        }

        public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        {
            // Not being used
        }

        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
        {
            // Not being used
        }
    }
}

I’m also taking the opportunity to apply the client’s default logo for the site upon activation of the feature.
Step 4: Put your theme into the solution and make sure it deploys to the TEMPLATE/THEMES folder and place any images into the appropriate folders within TEMPLATE/IMAGES.
Step 5: Build the WSP and deploy to SharePoint for testing. You will need to activate the feature on the Web Application before creating any new sites. When you create new sites, the feature should automatically be activated to deploy the custom theme branding to all news sites on that web application. There is plenty of room for improvement, so comments are welcome!

2 comments:

MartyNZ said...

Very nice, but how about the application pages?

Chris said...

In this scenario, our client was looking for simple branding and they were not concerned about the application pages. From everything I've read about application pages, they remain one of the more difficult customizations in SharePoint. I'm sure it can be done, but I haven't had a client with that requirement (yet) so I haven't had a need to dive into that type of customization.