Friday, September 24, 2010

Create custom sites in Sharepoint using site definitions: step by step guide - part 1

If you work with Sharepoint then this theme is most probably well known for you. Any business have its own requirements and rules many of which are not fulfilled with OTB Sharepoint functionality. In this case we perform customization of OTB features for real life business needs.  With this article I would like to start a series of post where I will try to describe one of the important and widely required customizations: creation of custom sites in Sharepoint using custom site definitions. I will deep inside the process of site creation in Sharepoint mostly from developer point of view, i.e. creation and customization of sites using Sharepoint Designer are out of scope. Another purpose of this posts is to have a reference guide for forums threads I participate in.

Lets say we have a company which has many branches all over the world. We have a requirement to create a Sharepoint-based portal which will have own sub sites for each branch (for simplicity lets assume that we have single site collection per company with root site http://www.contoso.com. Branches will have the following URLs http://www.contoso.com/usa, http://www.contoso.com/europe, etc). Sites of all branches have more or less the same well known structure (i.e. its own sub sites, lists, pages, web parts) and settings (security settings, navigation, etc). Lets say they will have the following sub sites:

   1: root
   2:  |
   3:  |----USA
   4:  |    |
   5:  |    |----Sales
   6:  |    |----IT
   7:  |    |----HR
   8:  |
   9:  |----Europe
  10:  |    |
  11:  |    |----Sales
  12:  |    |----IT
  13:  |    |----HR
  14: ...

If company will open its branch in new country we need to have simple and fast process of creation of new site for this branch in company’s portal. Also we need to make this process very flexible and customizable for future business requirements changes.

As I already mentioned there are different ways to make customizations in Sharepoint. You can save site as template (.stp) and create a new site based on this template. Also you can use stsadm operations export and import and then customize new site via Sharepoint Designer. All these methods will require manual work from administrator. It is suitable solution when there are not so many sites with similar templates which should be created or if they are created rarely. But if company has thousands of branches and for each of them separate web site is needed then automation of site creation becomes crucial for business. In this case best option in my opinion is to use one of the Sharepoint extensibility points - custom site definitions. If you are not familiar with site definitions or you have confused by site template and site definition terms I recommend you to check this article first: Working with Site Templates and Definitions. Shortly site template is .stp file created using existing site. This file will not be modified once you created it. Site definition – is fully customizable definition of web site located in 12/Template/SiteTemplates folder in onet.xml files.

We will go further then most of examples about custom sites creation and consider custom site creation process, i.e. not only custom site definitions. Having custom site definition the only thing you can do – is to use OTB Create Site page (12/Templates/Layouts/newsbweb.aspx) and choose custom definition in template picker control. But what if we need specify some custom parameters which will be used during site creation? In this case we have to implement custom Create Site page as well. But lets go through the process step by step.

Lets start from creating Sharepoint artifacts for our branch sites. At first we need clearly understand what we want to create in terms of MOSS. In our case it is not simple site as it has several sub sites under it (Sales, IT, HR). Using Sharepoint terminology we need to create portal for branch which will have root site of branch and 3 mentioned sub sites. Don’t get messed with terms. From point of view of end users there is one top level portal http://www.contoso.com which have many sub sites according to each branch. But we know that each branch sub site is in turn also portal in terms of MOSS.

Ok when we know what we should create we also need to choose whether we will create site definitions of sites (members of portal) from scratch or we will use some existing Sharepoint site definition as a base with further customization. In this post we will consider 2nd variant and will use OTB Publishing Site web definition as this is very common requirement in real life scenarios – customization of publishing sites.

In order to create portal site definition we need to create webtemp file in 12/Template/{lcid}/XML folder, where {lcid} is a placeholder for those locales which you need to support. I.e. if you need to create company’s branch portal for English and Swedish languages you have to create 2 webtemp files in the following folders:

  • 12/Template/1033/XML – this is for English
  • 12/Template/1053/XML – this is for Swedish

You can read more about portal webtemp files in this article: Portal Site Template File. Lets name our file webtempContosoBranchSitePortal.xml. In our case it will have the following content:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <Templates>
   3:   <Template Name="ContosoBranchSitePortal" ID="10001">
   4:     <Configuration ID="0"
   5:       Title="Contoso Branch"
   6:       Description=""
   7:       ProvisionAssembly="Contoso.Branches, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a91ac4533350b8ae"
   8:       ProvisionClass="Contoso.Branches.BranchSitePortalProvisioningProvider"
   9:       ProvisionData="SiteTemplates\\ContosoBranchSitePortal\\ContosoBranchSitePortalWebManifest.xml"
  10:       RootWebOnly="FALSE"
  11:       Hidden="FALSE"
  12:       ImageUrl="/_layouts/images/stsprev.png"
  13:       DisplayCategory="Contoso" />
  14:   </Template>
  15: </Templates>

I will not repeat msdn and technet materials and describe all attributes here – you can find it using link I provided above. What is important for us now – is that we defined site template for portal with name “ContosoBranchSitePortal” and ID = 10001. Now if you will copy this file into 12 hive and make iisreset when you go to OTB Create Site page and specify this ID in query string (http://example.com/_layouts/newsbweb.aspx?ID=10001) you will see it in template picker control under Contoso category (DisplayCategory attribute in our webtemp file):

01

Notice about 2 attributes in webtempContosoBranchSitePortal.xml: ProvisionAssembly and ProvisionClass. Like in many other places in Sharepoint they contain assembly full name and fully qualified class name which will be used at some point of provisioning. When you use Publishing Site definition as base definition for portal you will need to use OTB PortalProvisioningProvider class from Microsoft.SharePoint.Publishing assembly. But in our case this is custom portal provisioning provider which is executed when portal is provisioned. In this example I want to show as much customization opportunities as possible so instead of OTB portal provisioning provider I used custom one. This is quite powerful technique which allows you to execute the code before or after provisioning. Unfortunately PortalProvisioningProvider class is sealed so you can’t just inherit it in your custom provider. But you can aggregate it as shown in the following code:

   1: namespace Contoso.Branches
   2: {
   3:     public class BranchSitePortalProvisioningProvider : SPWebProvisioningProvider
   4:     {
   5:         public override void Provision(SPWebProvisioningProperties props)
   6:         {
   7:             // todo: add code which will run before provisioining
   8:             var publishingPortalProvisioningProvider = new PortalProvisioningProvider();
   9:             publishingPortalProvisioningProvider.Provision(props);
  10:             // todo: add code which will run after provisioning
  11:         }
  12:     }
  13: }

As shown on example you can customize creation process by adding code which will run before (when no sub sites were created yet) and after provisioning (where all portal structure is ready). But where and how this structure is defined? The answer is in portal web manifest defined in ProvisionData attribute in webtempContosoBranchSitePortal.xml file:

ProvisionData="SiteTemplates\\ContosoBranchSitePortal\\ContosoBranchSitePortalWebManifest.xml

As you probably know 12/Template/SiteTemplates folder is the location of site definitions in onet.xml files (see this article in msdn for more details about structure of onet.xml files). In short onet.xml file is the basic element in site provisioning process in Sharepoint. It contains features, document templates, lists and other artifacts which will be provisioned into the site created based on configurations defined in this onet.xml file. But if you create a portal then instead of onet.xml file you should place portal web manifest which contains portal structure with references to another site definitions. In our case this is ContosoBranchSitePortalWebManifest.xml file in ContosoBranchSitePortal folder:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <!-- _lcid="1033" _version="12.0.4518" _dal="1" -->
   3: <!-- _LocalBinding -->
   4: <portal xmlns="PortalTemplate.xsd">
   5:   <web name="Home" siteDefinition="ContosoBranchSite#0" displayName="$Resources:ContosoBranch,Site_Home_DisplayName;" description="">
   6:     <webs>
   7:       <web name="Sales" siteDefinition="ContosoBranchSite#1" displayName="$Resources:ContosoBranch,Site_Sales_DisplayName;" description="" />
   8:       <web name="IT" siteDefinition="ContosoBranchSite#2" displayName="$Resources:ContosoBranch,Site_IT_DisplayName;" description="" />
   9:       <web name="HR" siteDefinition="ContosoBranchSite#3" displayName="$Resources:ContosoBranch,Site_HR_DisplayName;" description="" />
  10:     </webs>
  11:   </web>
  12: </portal>

As you can see we defined root site (Home) and 3 subsites (Sales, IT and HR). Name attributes will be used as URLs of sub sites (except root site of portal where URL is specified in Create Page) and displayName attribute contains localizable titles of web sites (resource file ContosoBranch.resx should be located in 12/Resources folder as well as its localized versions like ContosoBranch.en-us.resx). Most important attribute here is siteDefinition. It tells Sharepoint what site definition should be used for each site of portal. I.e. for Sales sub site MOSS will use site definition ContosoBranchSite#1.

But what does it mean and how to create site definitions I will describe in next part of the series. Also in next parts I will show how to customize Create Site page and many other interesting things.

Update 2010-10-28: 2nd part of the series is posted here.

2 comments:

  1. In your example how does the company compile global reports by department globally(i.e. HR report for all countries combined)? Another question lets say the U.S. branch makes upper level decisions of the Europe I.T department. Europe tracks all its own I.T. assets but the U.S. branch has to approve the purchase. Is it esaier to make gloabl departments with branch office views? how would you set the view for the branch for all lists in the H.R. site?

    ReplyDelete
  2. bcobra,
    your questions are related more with data management and data aggregation, not with site creation. If you need to show reports with data for all countries you may use e.g. SPSiteDataQuery or search scopes, depending on your needs. About second question: if USA branch have to approve something in Europe site, add people from USA to appropriate security group on Europe site (if you are talking about OTB approval workflow).

    ReplyDelete