« No internet access?!? | Main | Gnomz Software »

June 05, 2007

Automatically Applying SharePoint Themes

A recent issue I encountered is that SharePoint 2007 does not, by default, apply a parent site's theme to any newly created child sites.  While this can be effective for a small departmental intranet, it is not effective for a highly governed enterprise intranet.  When a user creates a site, it should automatically have the standard corporate theme applied to it.

So, where does that leave us?  Thankfully you can wire in all sorts of custom code with SharePoint Features and Site Template Associations.  In the rest of this post I will outline the steps required to solve the problem I mentioned, and you will find that these steps can apply to a multitude of related scenarios.

Step 1: The Theme Feature

Beause the SharePoint theme is not automatically propogated to any child sites, you will need to leverage custom code based on the SharePoint API to set the theme.  To do this we will create a SharePoint Feature with an Event Receiver class that will perform the setting of the theme when the Feature is activated.

<Feature  Id="477770BB-C970-41af-8374-56BEA2DC2245"

          Title="My Corporate Theme"

          Description="Applies the Corporate Theme to this site."

          Version="1.0.0.0"

          Scope="Web"

          Hidden="false"

          DefaultResourceFile="core"

          xmlns="http://schemas.microsoft.com/sharepoint/"

          ActivateOnDefault="true"

          ReceiverAssembly="MyCorp.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d245b3ed42dababd"

          ReceiverClass="MyCorp.SharePoint.MyCorpThemeEventReceiver"

          >

    <Properties>

        <Property Key="DefaultTheme" Value="none" />

        <Property Key="ThemeToApply" Value="Obsidian" />

    </Properties>

</Feature>

The Feature element for this Feature is set to a Web scope.  This is done because we want this Feature to be activatable with each site that is created, rather than only once as part of the site collection, web application, or farm.

An Event Receiver is also specified for this Feature.  The Event Receiver is where the real action takes place, and I have outlined those details below.

You will notice that I have specified some properties for the Feature element.  This allows me to dynamically provide the theme value instead of hardcoding it.  Feature Properties can be used for any sort of dynamic Feature configuration, so make sure to keep them in mind when designing your Features.

using System;

using System.Collections.Generic;

using System.Text;

using Microsoft.SharePoint;

namespace MyCorp.SharePoint

{

    public class MyCorpThemeEventReceiver : SPFeatureReceiver

    {

        #region Constants

        private const string Property_DefaultTheme = "DefaultTheme";

        private const string Property_ThemeToApply = "ThemeToApply";

        #endregion

        #region Abstract Methods

        public override void FeatureInstalled(SPFeatureReceiverProperties properties)

        {

            //throw new Exception("The method or operation is not implemented.");

        }

        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)

        {

            //throw new Exception("The method or operation is not implemented.");

        }

        #endregion

        #region Feature Receiver Methods

        public override void FeatureActivated(SPFeatureReceiverProperties properties)

        {

            SPSite site = properties.Feature.Parent as SPSite;

            SPWeb web = properties.Feature.Parent as SPWeb;

            if (site != null)

            {

                web = site.RootWeb;

            }

            if (web != null)

            {

                if (properties.Feature.Properties[Property_ThemeToApply] != null)

                {

                    string theme = properties.Feature.Properties[Property_ThemeToApply].Value;

                    if (!string.IsNullOrEmpty(theme))

                    {

                        web.ApplyTheme(theme);

                    }

                }

            }

        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

        {

            SPSite site = properties.Feature.Parent as SPSite;

            SPWeb web = properties.Feature.Parent as SPWeb;

            if (site != null)

            {

                web = site.RootWeb;

            }

            if (web != null)

            {

                if (properties.Feature.Properties[Property_DefaultTheme] != null)

                {

                    string theme = properties.Feature.Properties[Property_DefaultTheme].Value;

                    if (!string.IsNullOrEmpty(theme))

                    {

                        web.ApplyTheme(theme);

                    }

                }

            }

        }

        #endregion

    }

}

The Event Receiver class outlined above performs a simple task.  During activation it determines the Feature's parent (either an SPSite or SPWeb) and then sets a new theme for the associated SPWeb instance.  Simple enough, right?  Notice that on deactivation the reverse is performed.  This provides for a clean removal of features, without leaving any orphaned settings.

At this point you have a SharePoint Feature that will apply a dynamically specified theme upon activation.  This in itself isn't any more sophisticated than having a user select a theme themselves after creating a new site.  Where it really becomes powerful is when we utilize Site Template Associations for activating this Feature when sites are created based on a specified site template.

Step 2: The Site Template Association Feature

Now that we have a Feature that will automatically apply a specified theme, what we need to do now is make sure that Feature is activated each time a site is created.  To do this we will create another Feature for associating our Theme Feature with a few specific site templates.

<Feature  Id="A138151F-2AF5-4a4d-890B-DD46B98302A3"

          Title="My Corporate Theme Stapling"

          Description="Staples the My Corporate Theme Feature to all sites."

          Version="1.0.0.0"

          Scope="Farm"

          Hidden="true"

          DefaultResourceFile="core"

          xmlns="http://schemas.microsoft.com/sharepoint/"

          ActivateOnDefault="true"

          >

    <ElementManifests>

        <ElementManifest Location="SiteAssociations.xml" />

    </ElementManifests>

</Feature>

The Feature element for this Feature is set to Farm scope.  This is done because we want to associate our Theme Feature with all site templates across all web applications and site collections.  This can be particularly powerful if you have multiple SharePoint applications running on the same infrastructure and you want them all to have the same theme applied to newly created sites.

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

    <!-- <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="GLOBAL#0" /> -->

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SPSMSITE#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SPSPERS#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="OSRV#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="STS#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="STS#2" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="MPS#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="MPS#1" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="MPS#2" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="MPS#3" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="MPS#4" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="WIKI#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="BLOG#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="BDR#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="EAWF#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="OFFILE#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="OFFILE#1" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="PWA#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="PWS#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SPS#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SPSMSITE#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SPSTOC#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SPSTOPIC#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SPSNEWS#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SPSNHOME#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SPSSITES#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SPSBWEB#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SPSCOMMU#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SPSREPORTCENTER#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SPSPORTAL#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="SRCHCEN#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="PROFILES#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="CMSPUBLISHING#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="BLANKINTERNET#0" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="BLANKINTERNET#1" />

    <FeatureSiteTemplateAssociation Id="477770BB-C970-41af-8374-56BEA2DC2245" TemplateName="BLANKINTERNET#2" />

</Elements>

Notice that I have specified which site templates I would like to associate my Theme Feature with (the Id value is the Feature Id value of the Theme Feature).  You can optionally provide the site template "GLOBAL#0" (commented out), which will then associate the Theme Feature with all site templates, rather than listing them all out.  However, the downside with this approach is that the Theme Feature will *not* be automatically activated.  SharePoint seems to only activate the Feature if you specify the site template specifically.

Step 3: Deploy!

I won't go into the details of deploying SharePoint Features as there are lots of articles based on that.  Suffice to say, once you deploy these two new Features you will notice that your newly created sites have the specified theme applied to them.

Good luck!

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d834f25dc169e200df351f01558833

Listed below are links to weblogs that reference Automatically Applying SharePoint Themes:

Comments

Hi,

I've tried feature stapling to GLOBAL (and GLOBAL#0) but my feature is not activated automatically on new site creation?? The feature works when manually activated and has scope=Site. I've tried other template types such as BDR#0, STS#0 and MPS#0

Features cannot be automatically activated at Site/Web scope.

Which basically means that if you dont manually activate the feature when a site is created, your going to have to ask your users to do it for you.

Graham,

thanks for your great article! I enjoyed reading it and had the features implemented in a couple of hours. Works like a charm!

Alex

excellent post, very useful

Nice article, thanks for sharing!

Thanks Dennis, you may also want to check out the follow-up article located at http://www.grahamzero.com/blog/2008/05/dynamic-staplin.html

The Feature is working fine. but when i create a new site in teh same site collection, the theme is not effected for the newly created site.

Can any one find out what have i missed?

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been posted. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment