Following this guide you’ll see the process that goes behind creating the feature which commonly be used to deploy branding items such as Master Pages, CSS, JavaScript, & Themes. If you plan to follow along just replace the steps with my name with whatever you wish.

Configure the Project

  1. Open Visual Studio 2010
  2. File -> New -> Project

  1. Select SharePoint -> Empty SharePoint Project
  2. Add Name: TomDaly.SharePoint.Branding (this is my standard structure)
  3. Add Location: C:\Projects\TomDaly

  1. Click OK
  2. Enter your test site for debugging purposes.
  3. Select ‘Deploy as farm solution’

  1. Click Finish

Adding the CSS / Image / JavaScript Files

Add CSS file

  1. Right Click on the Project -> Add -> SharePoint ‘Layouts’ Mapped Folder

  1. This created a folder which is mapped to the layouts

** These files in here are accessible through the web via http://YOURSITE/_layouts/TomDaly.SharePoint.Branding/

  1. Right click on Layouts\TomDaly.SharePoint.Branding folder -> Add -> New Item

  1. Select Web on the left, and Style Sheet on the right, and Name the file at the bottom.

(I typically use base.css or style.css for the foundation of my styles, but this is all up to you)

  1. Click Add

Add Images & JavaScript Folder

This would be the location for any images associated with the site css.

  1. Right Click on the Layouts\TomDaly.SharePoint.Branding folder -> Add -> New Folder

  1. Name the folder ‘images’

OPTIONAL STEP

  1. Repeat Step 1 & 2 for the JavaScript folder. (I typically call this folder ‘js’)

I usually include a JavaScript folder because most of the time I end up using jQuery somewhere on the site, this is where I store those files which I would reference on page or in the Master Page. Depending on how it’s needed.

These files would be accessible: http://YOURSITE /_layouts/TomDaly.SharePoint.Branding/js/JSFILESHERE

Setting up the Feature

  1. In your project Right click on Features -> Add Feature

This will create a feature with some default name of ‘Feature 1’, which we don’t want

  1. Select Feature1, Right Click -> Rename

  1. Rename the Feature to TomDaly.SharePoint.Branding (I typically name it to the same as the project name)

  1. Double Click on your Primary feature, in the main left hand window the properties should appear

  1. Give your feature a normal title name Title and Description, and scope it accordingly. (I usually scope my master pages to (Site) as they are normally used through the site collection

  1. Click Save

Renaming the WSP

This is really annoying to me so I always change it. When a .WSP is generated it will usually come out as Feature_Feature.wsp. I prefer just Feature.wsp.

1. Double Click on the primary Feature, the Properties should appear right below it.

2. Change ‘Deployment Path’

From: $SharePoint.Project.FileNameWithoutExtension$_$SharePoint.Feature.FileNameWithoutExtension$

To: $SharePoint.Project.FileNameWithoutExtension$

Adding the Master Page

1. Right Click on the Project -> Add -> New Item

2. In the left Installed Template column, Select SharePoint 2010

3. On the right select Module

4. At the bottom name the Module, Master Pages

5. Click Add

** You module will be added to your project **

6. Under the Master Pages Module, right click on Sample.txt and Delete It

7. Now Drag & Drag and Drop your Custom Master Page from another folder into the project, In the Master Pages Module

8. Double Click on the Elements.xml in the Master Pages Module

9. In the Elements.xml file, make the following changes to the <Module> line

Change

<Module
Name=MasterPages>

To

<Module
Name=MasterPages
Url=_catalogs/masterpage>

10. In the Elements.xml file, make the following changes to the <File> line

a. add IgnoreIfAlreadyExists=True

b. add Type=GhostableInLibrary

c. remove MasterPages/ from the
Url=MasterPages/TOMDALY.master

So essentially this line

<File
Path=MasterPages\TOMDALY.master
Url=MasterPages/TOMDALY.master />

Changes to

<File
Path=MasterPages\TOMDALY.master
Url=TOMDALY.master
IgnoreIfAlreadyExists=True
Type=GhostableInLibrary />

11. Click Save

Adding Theme

This step will incorporate a theme into your project. How to generate the .thmx is not covered here but a simple way would be to export from PowerPoint or use ThemeBuilder to generate this file.

1. Right Click on the Project -> Add -> New Item

2. On the left Click SharePoint -> 2010

3. On the Right Select “Module”

4. Add Name: Theme

5. Click Add

6. In the Theme node, Delete Sample.Txt

7. Copy in you custom .thmx file

8. Double Click on the Elements.xml in the Theme Module

9. In the Elements.xml file, make the following changes to the <Module> line

Change

<Module
Name=Theme>

To

<Module
Name=Theme
Url=_catalogs/theme>

10. In the Elements.xml file, make the following changes to the <File> line

a. add IgnoreIfAlreadyExists=True

b. add Type=GhostableInLibrary

c. remove Theme/ from the
Url=Theme/TomDaly.thmx

So essentially this line

<File
Path=Theme\TomDaly.thmx
Url=Theme/TomDaly.thmx
/>

Changes to

<File
Path=Theme\TomDaly.thmx
Url=TomDaly.thmx
IgnoreIfAlreadyExists=True
Type=GhostableInLibrary />

11. Click Save

Adding the Feature Receiver

This whole step is optional. Its sole purpose is to automatically turn on the branding on the sites and subsites, apply a theme, or apply search master pages to your site collection. NOTE: If you changed the scope then there is no guarantee that this code will work.

Please take some time to look through the code as there are different sections you might want to comment out or fill in. Say if you want to configure the Site Logo or an Alternative CSS file. If you not interested and just want a working project jump down to the END and in the summary there is a link to download the project.

1. Right Click your primary Feature, Select Add Event Receiver

** This will get added Right under your feature**

2. Double Click on the new file TomDaly.SharePoint.EventReciever.cs

5. At the very top Add the following using statements

using Microsoft.SharePoint.Utilities;

using System.Collections.ObjectModel;

7. Under the class declaration add these three string constants which contain the names of the masterpages and the theme.

So my master page name is TomDaly.master, my search master page which I don’t have a custom one for yet is minimal.master, and my Custom Theme is called TomDaly

8. Replace the public override void FeatureActivated, with

public override void FeatureActivated(SPFeatureReceiverProperties properties)

{

 SPSite site = properties.Feature.Parent as SPSite;

 if (site != null)

 {

  using(SPWeb topLevelSite = site.RootWeb)

  {

   //Get the relative path

   string relativePath = topLevelSite.ServerRelativeUrl;

   if (!relativePath.EndsWith("/"))

   {

    relativePath += "/";

   }

   //Get Theme collection from site and the them we want

   ReadOnlyCollection < ThmxTheme > themes = ThmxTheme.GetManagedThemes(site);

   ThmxTheme customTheme = null;

   foreach(ThmxTheme theme in themes)

   {

    if (theme.Name == themeName)

    {

     customTheme = theme;

     break;

    }

   }

   //Apply branding to each web in the site collection

   foreach(SPWeb web in site.AllWebs)

   {

    //Apply masterpage and logo

    if (web.WebTemplate == "SRCHCENTERLITE" || web.WebTemplate == "SRCHCEN" || web.WebTemplate == "SRCHCENTERFAST")

    {

     web.CustomMasterUrl = relativePath + "_catalogs/masterpage/" + searchMasterPage;

    } else

    {

     web.MasterUrl = relativePath + "_catalogs/masterpage/" + masterPage;

     web.CustomMasterUrl = relativePath + "_catalogs/masterpage/" + masterPage;

    }

    web.AlternateCssUrl = "";

    web.SiteLogoUrl = "";

    web.UIVersion = 4;

    web.Update();

    //Also apply the theme

    if (customTheme != null)

    {

     customTheme.ApplyTo(web, true);

     web.Update();

    }

   }

  }

 }

}

9. Replace the public override void FeatureDeactivated, with

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

{

 SPSite site = properties.Feature.Parent as SPSite;

 if (site != null)

 {

  using(SPWeb topLevelSite = site.RootWeb)

  {

   //Get the relative path

   string relativePath = topLevelSite.ServerRelativeUrl;

   if (!relativePath.EndsWith("/"))

   {

    relativePath += "/";

   }

   //Apply branding to each web the wen the site collection

   foreach(SPWeb web in site.AllWebs)

   {

    //Apply default masterpage and logo

    if (web.WebTemplate == "SRCHCENTERLITE" || web.WebTemplate == "SRCHCEN" || web.WebTemplate == "SRCHCENTERFAST")

    {

     web.CustomMasterUrl = relativePath + "_catalogs/masterpage/minimal.master";

    } else

    {

     web.MasterUrl = relativePath + "_catalogs/masterpage/v4.master";

     web.CustomMasterUrl = relativePath + "_catalogs/masterpage/v4.master";

    }

    web.AlternateCssUrl = "";

    web.SiteLogoUrl = "";

    web.Update();

    //reset the theme back to default

    ThmxTheme.SetThemeUrlForWeb(web, null, true);

    web.Update();

   }

  }

 }

}

10. Click Save

11. Hit F6, or Build -> Build Solution … to ensure that everything is correct and ok. You should receive the “Build Succeed” in the bottom left corner

Changing the Site Url for Testing

Sometimes you want to create or re-use this package and you need to change the url of the site to deploy to.

1. Click on the project and in the Properties window you’ll notice the Site URL

2. Change that to your new site destination

3. Click Save

Deployment

If you’re testing on a development box, that visual studio is on then you can simply deploy through visual studio. Otherwise you’ll have to push out your solution with the .wsp file.

Deploy from Visual Studio

1. In the Build Menu, Select Deploy

OR

Getting the .WSP for manual deployment

1. In the Build menu, Select Build to ensure no errors

2. In the Build menu, Select Package to generate the .WSP file

3. The files will be in the project folder, and by default in the BIN\DEBUG

Either way once you deploy your solution should be available in the Site Collection Features Gallery as shown here

Summary

So that’s how you setup a project for deploying branding assets. This is the typical setup I use but can change from client to client depending on their needs.

Download the entire project here.

Comments
  • Bijay
    Posted at 1:01 pm December 13, 2015
    Bijay
    Reply
    Author

    Great post, well explained with proper steps.

  • phil
    Posted at 11:22 pm April 28, 2015
    phil
    Reply
    Author

    Thanks Tom, and a big thanks to James as well! That note about removing the second web.Update() helped me as well.

  • Anant
    Posted at 9:16 pm June 24, 2013
    Anant
    Reply
    Author

    Great tutorial. Thanks very much Thomas. I’m a beginner developer and trying to understand how it all fits together. Your article helped me a lot. If you have put together one for building custom css and master page to move different sections around (e.g. moving site actions to right, adding another menu next to Site Actions mentu, hiding View All Site Actions from SiteActions and Left hand nav).
    This is quite difficult to understand so walkthrough really helps for beginners like myself.

  • user
    Posted at 4:35 pm March 30, 2013
    user
    Reply
    Author

    Excellent Tutorial

  • Ginni
    Posted at 9:19 am February 24, 2013
    Ginni
    Reply
    Author

    Hi Thomas,

    I am using the same Master page and CSS which is attached in this BLOG.

    or else Please let me know your e-mail details so that I can fwd it.

    Thanks
    Ginni.

    • Thomas Daly
      Posted at 9:48 am February 25, 2013
      Thomas Daly
      Reply
      Author

      That masterpage is for demonstration only. It is very specific as I’ve taken out, or hid, a few of the controls. The breadcrumbs are no long in that master page. Take a look at a v4.master and the class=’s4-titletext’ that is the section that has the breadcrumbs. If you continue to use the masterpage in the blog, you will see there is a hidden panel at the bottom that has PlaceHolderSiteName & PlaceHolderPageTitleInTitleArea which are used to make the breadcrumbs. You will have to move them up and back in because you can’t have duplicate place holders.

      • ginnimetlife
        Posted at 10:26 am February 25, 2013
        ginnimetlife
        Reply
        Author

        Thanks Thomas.

        I’ll try it and let you know abou that.

        Thanks in tons.

        Ginni.

  • ginnimetlifeinni
    Posted at 3:32 am February 8, 2013
    ginnimetlifeinni
    Reply
    Author

    Hi Thomas.

    You saved my day. It really worked for me. One thing i need to know, how did you add the fgor images in feature activation?

    Thanks.
    Ginni

    • Thomas Daly
      Posted at 7:56 am February 8, 2013
      Thomas Daly
      Reply
      Author

      Glad this helped. To add/change feature images, click on the feature & make sure you can see the property window. In there, there is a property for ImageUrl.

      • Ginni
        Posted at 12:44 pm February 16, 2013
        Ginni
        Reply
        Author

        Hi Thomas,

        Thanks for the reply. Again you helped me.

        As, I an trying to enable/show Breadcrumb right after the logo but I can not see the Breadcrumb.

        As I try to add SiteMapPath in masterpage but i did not help me.

        Could you help me out from here also.

        Thanks a lot.

        • Thomas Daly
          Posted at 12:58 pm February 21, 2013
          Thomas Daly
          Reply
          Author

          can you email me your masterpage & css – I can take a look at it.

  • Cat
    Posted at 3:45 pm November 26, 2012
    Cat
    Reply
    Author

    Thank you for this article. After I activate on the site collection, nothing happens–no change was made. I open the site in SharePoint Designer and I can see the master page there, but it hasn’t been set as default/custom. Any guidance on how to complete this step upon feature activation?

    • Thomas Daly
      Posted at 12:01 pm December 3, 2012
      Thomas Daly
      Reply
      Author

      Check your feature receiver, that’s where the code goes which gets executed when you activate. Make sure it’s apply the masterpage with that and do web.update();

  • Tony
    Posted at 6:51 am November 7, 2012
    Tony
    Reply
    Author

    Great step by step tutorial. Most people don’t realise how easy it is to package designs in a wsp. Event Handler section was very helpful.

    Tahnks,
    Tony

  • Casey
    Posted at 10:37 pm August 20, 2012
    Casey
    Reply
    Author

    Thanks for taking the time to reply. The problem was I had the pathing incorrect to the images. From the master page it is just /images/xxxx.png.

    Now on to deploying with power shell…

  • Casey Lee
    Posted at 9:27 pm August 17, 2012
    Casey Lee
    Reply
    Author

    Great article Tom! It worked great for my main site collection. I have seven site collections and the master page and CSS work fine just by changing the Site URL in visual Studio, but when I trying to do a different site collection my images are no where to be found. How do I make sure that my images are deployed to “Site Assets” on every site collection?

    • Thomas Daly
      Posted at 1:24 am August 18, 2012
      Thomas Daly
      Reply
      Author

      You can do 2 things. If the assets are going to be very much the same across all site collections then you can deploy them to the file system (layouts) folder or if you plan to make changes to the .css and images per site collection you can deploy them to the Style Library per site collection

      Option 1 – using _layouts ) make sure the reference to the images in the .css file point to /_layouts/YourFolder/images/your_image.jpg
      This way all site collections will locate the images

      Option 2 – deploy assets to Style Libray )
      a) In Visual Studio create a new module called “Style Library”, my elements.xml looks like this
      b) under there create I typically create a subfolder for the project name, for example “MyAssets”
      c) in that folder i’d create a subfolder for images & put the .css in the MyAssets folder.

      (PROJECT STRUCTURE)
      Style Library (module)
      +-> MyAssets (sub folder)
      |
      +-> MyStyle.css
      +-> images (sub folder)
      |
      +-> MyImage.jpg

      (ELEMENTS.XML)
      <?xml version="1.0" encoding="utf-8"?>
      <Elements xmlns="http://schemas.microsoft.com/sharepoint/"&gt;
      <Module Name="Style Library" Url="Style Library" RootWebOnly="TRUE">
      <File Path="Style LibraryMyAssetsimagesMyImage.jpg" Url="MyAssets/images/MyImage.jpg" Type="GhostableInLibrary" />
      <File Path="Style LibraryMyAssetsMyStyle.css" Url="MyAssetsMyStyle.css" Type="GhostableInLibrary" />
      </Module>
      </Elements>

      There is a section in this guide, that I don’t think works as they describe it. It seems like dragging and dropping files into the project and Style Library modules didn’t properly auto-add them to the .xml file. I found that the file never show in the Style Library unless I specify Type=”GhostableInLibrary”
      http://msdn.microsoft.com/en-us/library/gg447066.aspx

  • James
    Posted at 12:46 pm August 5, 2012
    James
    Reply
    Author

    Awesome post!

    Just a note about applying the theme to a web. The bit where you apply the theme:

    theme.ApplyTo(web, true);
    web.update();

    For me, this caused an exception “The web being updated was changed by an external process”. It turns out that the theme.ApplyTo() method internally calls an Update() on the web itself, so your second update() call is on a ‘stale’ web. I fixed this by simply NOT calling update() after theme.AppyTo(), anfd it still works.

  • Leave a Reply to Tony
    Cancel Reply

    This site uses Akismet to reduce spam. Learn how your comment data is processed.