MOSS MVP

I've moved my blog to http://blog.falchionconsulting.com!. Please update your links. This blog is no longer in use--you can find all posts and comments at my new blog; I will no longer be posting to this site and comments have been disabled.

Monday, January 28, 2008

Apply Theme

This command came about as a result of wanting to be able to reset the theme of a web site when it was upgraded. I had created this code as part of the upgrade2 command and figured that I might as well pull it out into its own command so that it could be used independently of the upgrade command. I called this command gl-applytheme. Setting the theme is really simple - you just call the SPWeb object's ApplyTheme() method and pass in the theme ID. The theme ID for OTB themes can be found in the SPThemes.xml file located in the ..\12\Layouts\Templates\[LCID] folder. The core code can be seen below:

   1: internal static void ApplyThemeToWeb(string theme, string url, bool recurse)
   2: {
   3:  using (SPSite site = new SPSite(url))
   4:  using (SPWeb web = site.AllWebs[Utilities.GetServerRelUrlFromFullUrl(url)])
   5:  {
   6:   ApplyThemeToWeb(theme, web, recurse);
   7:  }
   8: }
   9:  
  10: internal static void ApplyThemeToWeb(string theme, SPWeb web, bool recurse)
  11: {
  12:  web.ApplyTheme(theme);
  13:  
  14:  if (recurse)
  15:  {
  16:   foreach (SPWeb subWeb in web.Webs)
  17:   {
  18:    try
  19:    {
  20:     ApplyThemeToWeb(theme, subWeb, recurse);
  21:    }
  22:    finally
  23:    {
  24:     subWeb.Dispose();
  25:    }
  26:   }
  27:  
  28:  }
  29: }

The syntax of the command can be seen below:

C:\>stsadm -help gl-applytheme

stsadm -o gl-applytheme

Applies the specified theme to the specified site.

Parameters:
        -url <url of the web to update>
        -theme <id of the theme to apply (see C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\Layouts\1033\SPThemes.xml for template IDs>
        [-recurse (applies change to all sub-webs)]
Here's an example of how to set the theme for a web to it's default:
stsadm -o gl-applytheme -url "http://intranet" -theme none -recurse
Note that sub-sites of a site collection will use the theme specified for the root site collection unless explicitly set. This means that you can set the theme for an entire site collection by just setting the root without setting the sub-sites. If you pass in the recurse flag then it will set the theme for each sub-site explicitly which means that future changes to the root web's theme will not affect the theme for sub-sites (this may or may not be what you want so make sure that you understand how this works).

14 comments:

Andy Burns said...

"Note that sub-sites of a site collection will use the theme specified for the root site collection unless explicitly set. This means that you can set the theme for an entire site collection by just setting the root without setting the sub-sites."

Not sure I understand - are you saying this is out-of-box behaviour, and are you sure about this? I've just tried it, and that wasn't what I saw happen. Site themes appear to be independent - even for the root site of a root site collection.

Do you have another feature installed? Some funky Site Definition maybe? Or, it just hit me - are you using the Alternate CSS URL on the master page configuration page?

Or are you saying that you can do that with the applytheme command? I looked at the code, but didn't see that.

What would be good would be to be able to:

- Set the theme for a site and all subsites (what you've already written)
- Replace a theme on a site and all subsites with another theme (i.e. swap Theme A for Theme B, although there might be some sites in the tree using Theme C)
- 'Refresh' a theme (which might just be replacing Theme A with Theme A). This would be good for solving the problem here - http://www.heathersolomon.com/blog/archive/2008/01/30/SharePoint-2007-Design-Tip-Import-your-CSS-for-SharePoint-Themes.aspx

Very neat idea though - I was thinking about writing something similar (except I'd put it into the Site Admin pages).

Would be happy to help by writing some of this - your code is straight forward enough.
Email andy at the domain novolocus.com

Gary Lapointe said...

I'd have to look at it again but the behavior I described was what I witnessed - changing the theme of the root web (site collection) resulted in all sub-sites using the specified theme - if I set the theme for a specific sub-site then changing it at the root level did not affect the sub-site.

It probably wouldn't take much to modify the code to support the "refresh" ability you suggest - just a matter of deleting the "_theme" folder (may not be necessary) and re-setting the theme (the same ability can basically solve the "replace" ability you mention).

Anonymous said...

After applying the theme using this extension, when I go to http://[sitepath]/_layouts/themeweb.aspx, the applied theme is not highlighted. Is there some additional setting required to make this right? Not a big deal, but just for completeness...

Thanks for these great extensions!
M.

Anonymous said...

re: my prior comment about seeing the applied theme highlighted at http://[sitepath]/_layouts/themeweb.aspx... Case matters, i.e., you need to apply "Wheat", not "wheat" to have it be highlighted.

I'd also be interested in "resetting" the theme, as well as applying (or resetting) the them for all subsites. I'd be happy to collaborate. marc dot anderson at jornata dot com.

Thanks again...

Anonymous said...

I'm trying to get this one up and running. It builds just fone and the package deploys just fine, but when I run it, I get this:

H:\SharePoint\MyStsAdmCommands\Package\Debug>stsadm -o ss-applytheme

Value cannot be null.
Parameter name: type

Any ideas?

Gary Lapointe said...

That error occurs when the dll cannot be found (i.e., it's not in the GAC). I'm assuming that you replaced "gl-" with "ss-" which is fine and shouldn't affect anything. Make sure the dll is GAC'd and you should okay.

OIG said...

Gary,

Great post and description on how to Apply a Theme via the STSADM extensions you have developed.

In order to add a command to your list, could you show us how to do the same for a custom master page? Basically, same need, apply the custom master page to the Site Collection (top level) and Sub-Sites. In addition, when a new sub-site is created, for that sub-site to inherit the Custom Master Page from the Site Collection (top level).

Thanks,

OIG

Gary Lapointe said...

OIG - check out this blog post: http://www.beckybertram.com/index.php/2007/10/14/apply_custom_master_page_globally

In it you'll find everything you need to write your own code to do all of what you ask (it's much better to do this as a feature receiver as described but you could modify the code to run via an stsadm command).

okansafi said...

Here is the updated location of the page:

http://www.beckybertram.com/oldblog/index.php?p=33&more=1&c=1&tb=1&pb=1

Yann said...

Hi, Gary,

When I run gl-applytheme to apply the root theme to all subwebs, I get a (translated from french) "a theme named 'theme_name1011' already exists on the server".
I use moss 2007 upgraded from wss2.0.

Yann

Sweet Sparky said...

Gary,
Once again, this does not seem to apply to all the site collections in the applications even with recurse flag turned on. Is it only for sub webs underneatht the root or should it work for all webs in the application.

Txhx

Gary Lapointe said...

Sparky - like the other commands you've commented on, this one too only works for one site collection at a time. You'll need to combine with powershell if you want to do more. Any commands that I have that operate on more than one site collection will have a scope parameter where you can specify web application, site collection, or web.

Sweet Sparky said...

Thanks. I have never used powershell. However I plan to download and try it. Would it be simple to make this gl-applytheme apply at an application level through powershell. Just wanted to make sure I go through the exercise and attempt something you have not published through this command.

Gary Lapointe said...

Run the following making sure to replace the http://portal url with your web apps URL and to set the theme ID for the theme parameter:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$webApp = [Microsoft.SharePoint.Administration.SPWebApplication]::Lookup("http://portal")
$webApp.Sites | ForEach-Object {
stsadm -o gl-applytheme -url "$($_.Url)" -theme "theme ID" -recurse
}