Sue Hernandez's SharePoint Blog

SharePoint and Related Stuff

Category Archives: Master Template

MOSS – Nested Master Pages

In my first post, Moss Global Custom Master Template, I explained how to create a single custom master page as a feature, and then “Staple” that feature to site definitions (such that it will automatically activate for new sites).

In this post, we’ll talk about the challenges and pitfalls of making a Parent/Child Master Template (a Nested Master Template). The reason we may wish to have a Parent/Child template arrangement is so that we can control a “fixed” area of the page (the Parent), while allowing the Administrators to customize or brand the rest of the page (the Child).

There are 2 ways of approaching this challenge – (1) have an “orphaned” Parent, where the Parent Master page only has minimal code and a placeholder for the bulk of the code; and (2) have a full set of code for both Parent and Child such that they each can stand alone. We will take the second approach.

Design
We will create a template where we can “claim” the very top and the very bottom of the page for our Parent. We will put a custom Web Part in the very top bar, and we will put some disclaimer text and some links on the bottom.

Challenges
We will notice when we create a Parent/Child that there are 2 very big problems: (1) You cannot stop anyone with the appropriate SharePoint Designer rights from unghosting (customizing) both of the master pages; and (2) If you unghost (customize) the Child Master Page (which is the whole point of the excercise), you actually have to also unghost the Parent Master Page, or you break the web site.

The Code
View the HTML code for the templates at the very bottom of the post.

  • Open your site with SharePoint Designer.
  • Open the _catalogs/masterpage folder
  • Right-click on the masterpage folder and select New –> ASPX page.
  • Rename the page YourName.master, where “YourName” is the name you wish to make your custom Parent Master page.
  • Open the YourName.master page, and copy the code in from the Parent Master code sample. Don’t forget, if you copy and paste directly from Word, you get all of Word’s formatting, so I generally copy the code to Notepad first, then copy it over to Designer.
  • Save the page. Right-click the YourName.master page and select “Set as Default Master Page”
  • Set as Default Master Page

    Set as Default Master Page

  • You will be warned that you might break the page. Select OK. (or Yes)
  • Before you do anything with the Child Master page, view the default.aspx page with this master in the browser, and ensure that it loads correctly
    Default.aspx page

    Default.aspx page

  • Here are the images for the readers/viewers in case you like that feature of the Master Page (put them in the Layouts Images folder):
    DOC XLS PDF ZIP PPT
  • Right-click on the masterpage folder and select New –> ASPX page.
  • Rename the page YourName-Child.master, where “YourName” is the same name as your Parent Master page.
  • Open the YourName-Child.master page, and copy the code in from the Child Master code sample.
  • Save the page. Right-click the YourName-Child.master page and select “Set as Custom Master Page” .

All of the code inside the “PlaceHolderMainBase” inside of the Parent gets overridden by the Child. However, we need that code there so that the page is “complete” and standalone – i.e. can function as a master by itself. As many references out there in blog-land will tell you, there are certain placeholders you need by default for the page to work, whether you’re using them or not.

Taking it a step further
OK we did all of this in SharePoint Designer, right? What if we want this to be the default for all new sites, that is where my first article comes into play. We need, however, to make some modifications to the code in the Feature Receiver.

Namely, we have to add variables for BOTH the parent and child masters, as well as to set the web.MasterUrl property to the Parent, and the web.CustomMasterUrl to the Child.

 

 

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
  try
  {
    using (SPWeb web = (SPWeb)properties.Feature.Parent)
    {
      string customURLtoUsePARENT = customizedMasterUrlPARENT;
      string customURLtoUseCHILD = customizedMasterUrlCHILD;

      //Store the old Master URL's and Custom Master URL's
      web.AllProperties["OldMasterUrl"] = web.MasterUrl;
      web.AllProperties["OldCustomMasterUrl"] = web.CustomMasterUrl;
 
      //Assign the Master URL to both properties
      web.MasterUrl = customURLtoUsePARENT;
      web.CustomMasterUrl = customURLtoUseCHILD;

      //Update the Web
      web.Update();
    }
  }
  catch { }
}

You may also wish to remove BOTH files in the FeatureDeactivating function.

Finally, instead of stapling the feature to GLOBAL, we need to specify the templates. Namely, all of them except for the Meeting Workspaces templates. This is due to a SharePoint bug where if you create a meeting workspace from a recurring Calendar event, if you try to staple a feature to the new meeting workspace site, it breaks the scripting on the page such that you cannot switch dates.

<elements xmlns="http://schemas.microsoft.com/sharepoint/">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="STS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="STS#1">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="STS#2">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="WIKI#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLOG#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BDR#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="EAWF#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="OFFILE#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="OFFILE#1">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="PWA#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="PWS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSMSITE#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSTOC#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSTOPIC#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSNEWS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSNHOME#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSSITES#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSBWEB#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSCOMMU#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSREPORTCENTER#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSPORTAL#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SRCHCEN#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="PROFILES#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="CMSPUBLISHING#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLANKINTERNET#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLANKINTERNET#1">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLANKINTERNET#2">
</elements>

PARENT MASTER PAGE

<%@Master%>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="wssuc" TagName="Welcome" src="~/_controltemplates/Welcome.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="DesignModeConsole" src="~/_controltemplates/DesignModeConsole.ascx" %>
<HTML dir="<%$Resources:wss,multipages_direction_dir_value%>" runat="server" xmlns:o="urn:schemas-microsoft-com:office:office" __expr-val-dir="ltr">
<HEAD runat="server">
<META Content="Microsoft SharePoint">
<META Content="SharePoint.WebPartPage.Document">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
<META HTTP-EQUIV="Expires" content="0">
<SharePoint:RobotsMetaTag runat="server"/>
<Title> <asp:ContentPlaceHolder runat="server" /></Title>
<SharePoint:CssLink runat="server"/>
<SharePoint:Theme runat="server"/>
<SharePoint:ScriptLink Defer="true" runat="server"/>
<SharePoint:CustomJSUrl runat="server"/>
<SharePoint:SoapDiscoveryLink runat="server"/>
<SharePoint:DelegateControl runat="server" ControlId="AdditionalPageHead" AllowMultipleControls="true"/>
<asp:ContentPlaceHolder runat="server" />
</HEAD>
<BODY scroll="yes">
<form runat="server">
<WebPartPages:SPWebPartManager runat="Server"/>
<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%" HEIGHT="100%">
<tr><td><asp:ContentPlaceHolder runat="server">
<!-- ********************************************************
WARNING WARNING WARNING
Do not modify this master page.
********************************************************-->
<table CELLPADDING=0 CELLSPACING=0 BORDER=0 WIDTH="100%">
<tr>
<td colspan=4>
<span style="display:none">
<a href="#">
<SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,master_turnonaccessibility%>" EncodeMethod="HtmlEncode"/></a>
</span>
<A href="javascript:;" AccessKey="<%$Resources:wss,maincontent_accesskey%>" runat="server">
<SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,mainContentLink%>" EncodeMethod="HtmlEncode"/></A>
<table cellpadding=0 cellspacing=0 height=100%>
<tr>
<td style="padding-top: 2px;" height=100% valign=middle>
<div>
<span style="display:none">
<a href="#">
<SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,master_turnoffaccessibility%>" EncodeMethod="HtmlEncode"/></a>
</span>
<asp:ContentPlaceHolder runat="server">
<asp:SiteMapPath SiteMapProvider="SPSiteMapProvider" RenderCurrentNodeAsLink="true" SkipLinkText="" NodeStyle-CssClass="ms-sitemapdirectional" runat="server"/>
</asp:ContentPlaceHolder>
</div>
</td>
</tr>
</table>
<table cellpadding="0" cellspacing="0" height=100%>
<tr>
<td valign="middle" style="padding-left:3px; padding-right:6px;">
<SharePoint:DelegateControl runat="server" ControlId="GlobalSiteLink0"/>
</td>
<td valign="middle" style="padding-right:10px;">
YOUR TEXT OR WEB PART HERE
</td>
<td valign="middle">
<wssuc:Welcome runat="server" EnableViewState="false">
</wssuc:Welcome>
</td>
<td style="padding-left:1px;padding-right:3px;">|</td>
<td valign="middle">
<table cellspacing="0" cellpadding="0">
<tr>
<td>
<SharePoint:DelegateControl ControlId="GlobalSiteLink1" Scope="Farm" runat="server"/></td>
<td>
<SharePoint:DelegateControl ControlId="GlobalSiteLink2" Scope="Farm" runat="server"/></td>
</tr>
</table>
</td>
<td valign="middle">&nbsp;
<a href="javascript:TopHelpButtonClick('NavBarHelpHome')" AccessKey="<%$Resources:wss,multipages_helplink_accesskey%>" title="<%$Resources:wss,multipages_helplinkalt_text%>" runat="server"><img align='absmiddle' border=0 src="/_layouts/images/helpicon.gif" alt="<%$Resources:wss,multipages_helplinkalt_text%>" runat="server"></a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</asp:ContentPlaceHolder></td></tr>
<asp:ContentPlaceHoldermso-bidi-font-weight: normal">PlaceHolderMainBase" runat="server" >
<!-- ********************************************************
The code below is overridden in the Child Master Page
********************************************************-->
<tr><td>
<table width=100% cellpadding=0 cellspacing=0 border=0><tr>
<td>
<SharePoint:SiteLogoImage LogoImageUrl="/_layouts/images/logo.jpg" runat="server"/></td>
<td width=100%>
<asp:ContentPlaceHolder runat="server">
<h1>
<SharePoint:SPLinkButton runat="server" NavigateUrl="~site/">
<SharePoint:ProjectProperty Property="Title" runat="server" />
</SharePoint:SPLinkButton>
</h1>
</asp:ContentPlaceHolder>
</td>
<td style="padding-top:8px;" valign=top>
<asp:ContentPlaceHolder runat="server">
<SharePoint:DelegateControl runat="server" ControlId="SmallSearchInputBox"/>
</asp:ContentPlaceHolder>
</td>
</tr>
</table>
</td>
</tr>
<TR>
<TD WIDTH=100%>
<asp:ContentPlaceHolder runat="server">
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td nowrap valign="middle"></td>
<td-banner width=99% nowrap>
<asp:ContentPlaceHolder runat="server">
<SharePoint:AspMenu
Runat="server"
DataSourceID="topSiteMap"
EnableViewState="false"
AccessKey="<%$Resources:wss,navigation_accesskey%>"
Orientation="Horizontal"
StaticDisplayLevels="2"
MaximumDynamicDisplayLevels="1"
DynamicHorizontalOffset="0"
StaticPopoutImageUrl="/_layouts/images/menudark.gif"
StaticPopoutImageTextFormatString=""
DynamicHoverStyle-BackColor="#CBE3F0"
SkipLinkText=""
StaticSubMenuIndent="0"
CssClass="ms-topNavContainer">
<StaticMenuStyle/>
<StaticMenuItemStyle CssClass="ms-topnav" ItemSpacing="0px"/>
<StaticSelectedStyle CssClass="ms-topnavselected" />
<StaticHoverStyle CssClass="ms-topNavHover" />
<DynamicMenuStyle BackColor="#F2F3F4" BorderColor="#A7B4CE" BorderWidth="1px"/>
<DynamicMenuItemStyle CssClass="ms-topNavFlyOuts"/>
<DynamicHoverStyle CssClass="ms-topNavFlyOutsHover"/>
<DynamicSelectedStyle CssClass="ms-topNavFlyOutsSelected"/>
</SharePoint:AspMenu>
<SharePoint:DelegateControl runat="server" ControlId="TopNavigationDataSource">
<Template_Controls>
<asp:SiteMapDataSource
ShowStartingNode="False"
SiteMapProvider="SPNavigationProvider"
runat="server"
StartingNodeUrl="sid:1002"/>
</Template_Controls>
</SharePoint:DelegateControl>
</asp:ContentPlaceHolder>
</td>
<td-banner>&nbsp;&nbsp;</td>
<td valign=bottom align=right style="position:relative;bottom:0;left:0;">
<table cellpadding=0 cellspacing=0 border=0>
<tr>
<td>
<table height=100% cellpadding=0 cellspacing=0>
<tr>
<td>
<SharePoint:SiteActions runat="server" AccessKey="<%$Resources:wss,tb_SiteActions_AK%>"
PrefixHtml="&lt;div&gt;&lt;div&gt;"
SuffixHtml="&lt;/div&gt;&lt;/div&gt;"
MenuNotVisibleHtml="&amp;nbsp;">
<CustomTemplate>
<SharePoint:FeatureMenuTemplate runat="server"
FeatureScope="Site"
Location="Microsoft.SharePoint.StandardMenu"
GroupId="SiteActions"
UseShortId="true"
>
<SharePoint:MenuItemTemplate runat="server"
Text="<%$Resources:wss,viewlsts_pagetitle_create%>"
Description="<%$Resources:wss,siteactions_createdescription%>"
ImageUrl="/_layouts/images/Actionscreate.gif"
MenuGroupId="100"
Sequence="100"
UseShortId="true"
ClientOnClickNavigateUrl="~site/_layouts/create.aspx"
PermissionsString="ManageLists, ManageSubwebs"
PermissionMode="Any" />
<SharePoint:MenuItemTemplate runat="server"
Text="<%$Resources:wss,siteactions_editpage%>"
Description="<%$Resources:wss,siteactions_editpagedescription%>"
ImageUrl="/_layouts/images/ActionsEditPage.gif"
MenuGroupId="100"
Sequence="200"
ClientOnClickNavigateUrl="javascript:MSOLayout_ChangeLayoutMode(false);"
/>
<SharePoint:MenuItemTemplate runat="server"
Text="<%$Resources:wss,settings_pagetitle%>"
Description="<%$Resources:wss,siteactions_sitesettingsdescription%>"
ImageUrl="/_layouts/images/ActionsSettings.gif"
MenuGroupId="100"
Sequence="300"
UseShortId="true"
ClientOnClickNavigateUrl="~site/_layouts/settings.aspx"
PermissionsString="EnumeratePermissions,ManageWeb,ManageSubwebs,AddAndCustomizePages,ApplyThemeAndBorder,ManageAlerts,ManageLists,ViewUsageData"
PermissionMode="Any" />
</SharePoint:FeatureMenuTemplate>
</CustomTemplate>
</SharePoint:SiteActions>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</asp:ContentPlaceHolder>
</TD>
</TR>
<asp:ContentPlaceHolder runat="server">
<wssuc:DesignModeConsole runat="server"/>
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder runat="server">
<SharePoint:DelegateControl runat="server" ControlId="PublishingConsole"
PrefixHtml="&lt;tr&gt;&lt;td colspan=&quot;4&quot; id=&quot;mpdmconsole&quot; class=&quot;ms-consolemptablerow&quot;&gt;"
SuffixHtml="&lt;/td&gt;&lt;/tr&gt;">
</SharePoint:DelegateControl>
</asp:ContentPlaceHolder>
<TR height="100%"><TD><TABLE width="100%" height="100%" cellspacing="0" cellpadding="0">
<tr>
<td valign="middle" nowrap><div style="height:100%"><asp:ContentPlaceHolder runat="server"/></div></td>
<td>
<asp:ContentPlaceHolder runat="server">
<div><IMG SRC="/_layouts/images/blank.gif" width=1 height=100% alt=""></div>
</asp:ContentPlaceHolder>
</td>
<td valign=top class='ms-pagetitleareaframe' nowrap>
<table cellpadding=0 cellspacing=0 width=100% border="0">
<tr>
<td valign="top">
<asp:ContentPlaceHolder runat="server">
<asp:SiteMapPath SiteMapProvider="SPContentMapProvider" SkipLinkText="" NodeStyle-CssClass="ms-sitemapdirectional" runat="server"/> &nbsp;
</asp:ContentPlaceHolder>
</td>
</tr>
<tr>
<td height=100% valign=top>
<h2>
<asp:ContentPlaceHolder runat="server" />
</h2>
</td>
</tr>
</table>
</td>
<td>
<asp:ContentPlaceHolder runat="server"/>
<asp:ContentPlaceHolder runat="server">
<div style='height:100%'><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></div>
</asp:ContentPlaceHolder></td>
</tr>
<asp:ContentPlaceHolder runat="server"/>
<TR>
<TD valign=top height=100%>
<table-nav width=100% height=100% cellpadding=0 cellspacing=0>
<tr>
<td>
<TABLE height="100%"-navframe CELLPADDING=0 CELLSPACING=0 border="0">
<tr valign="top">
<td width="4px"><IMG SRC="/_layouts/images/blank.gif" width=4 height=1 alt=""></td>
<td valign="top" width="100%">
<asp:ContentPlaceHolder runat="server" />
<asp:ContentPlaceHolder runat="server" />
<asp:ContentPlaceHolder runat="server"/>
<asp:ContentPlaceHolder runat="server">
<div>
<div style="width:100%">
<h3><label>
<SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,quiklnch_pagetitle%>" EncodeMethod="HtmlEncode"/></label>
<Sharepoint:SPSecurityTrimmedControl runat="server" PermissionsString="ViewFormPages">
<div><SharePoint:SPLinkButton runat="server" NavigateUrl="~site/_layouts/viewlsts.aspx" Text="<%$Resources:wss,quiklnch_allcontent%>" AccessKey="<%$Resources:wss,quiklnch_allcontent_AK%>"/></div>
</SharePoint:SPSecurityTrimmedControl>
</h3>
<Sharepoint:SPNavigationManager
runat="server"
QuickLaunchControlId="QuickLaunchMenu"
ContainedControl="QuickLaunch"
EnableViewState="false">
<div>
<SharePoint:DelegateControl runat="server"
ControlId="QuickLaunchDataSource">
<Template_Controls>
<asp:SiteMapDataSource
SiteMapProvider="SPNavigationProvider"
ShowStartingNode="False"
StartingNodeUrl="sid:1025"
runat="server"
/>
</Template_Controls>
</SharePoint:DelegateControl>
<SharePoint:AspMenu
DataSourceId="QuickLaunchSiteMap"
runat="server"
Orientation="Vertical"
StaticDisplayLevels="2"
ItemWrap="true"
MaximumDynamicDisplayLevels="0"
StaticSubMenuIndent="0"
SkipLinkText=""
>
<LevelMenuItemStyles>
<asp:MenuItemStyle CssClass="ms-navheader"/>
<asp:MenuItemStyle CssClass="ms-navitem"/>
</LevelMenuItemStyles>
<LevelSubMenuStyles>
<asp:SubMenuStyle CssClass="ms-navSubMenu1"/>
<asp:SubMenuStyle CssClass="ms-navSubMenu2"/>
</LevelSubMenuStyles>
<LevelSelectedStyles>
<asp:MenuItemStyle CssClass="ms-selectednavheader"/>
<asp:MenuItemStyle CssClass="ms-selectednav"/>
</LevelSelectedStyles>
</SharePoint:AspMenu>
</div>
</Sharepoint:SPNavigationManager>
<Sharepoint:SPNavigationManager
runat="server"
ContainedControl="TreeView">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap>
<SharePoint:SPLinkButton runat="server" NavigateUrl="~site/_layouts/viewlsts.aspx" Text="<%$Resources:wss,treeview_header%>" AccessKey="<%$Resources:wss,quiklnch_allcontent_AK%>"/>
</td>
</tr>
</table>
</td>
</tr>
</table>
<div>
<SharePoint:SPHierarchyDataSourceControl
runat="server"
RootContextObject="Web"
IncludeDiscussionFolders="true"
/>
<SharePoint:SPRememberScroll runat="server" Style="overflow: auto;height: 400px;width: 150px; ">
<Sharepoint:SPTreeView
id="WebTreeView"
runat="server"
ShowLines="false"
DataSourceId="TreeViewDataSource"
ExpandDepth="0"
SelectedNodeStyle-CssClass="ms-tvselected"
NodeStyle-CssClass="ms-navitem"
NodeStyle-HorizontalPadding="2"
SkipLinkText=""
NodeIndent="12"
ExpandImageUrl="/_layouts/images/tvplus.gif"
CollapseImageUrl="/_layouts/images/tvminus.gif"
NoExpandImageUrl="/_layouts/images/tvblank.gif"
>
</Sharepoint:SPTreeView>
</Sharepoint:SPRememberScroll>
</div>
</Sharepoint:SPNavigationManager>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tr><td>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tr><td nowrap>
<SharePoint:SPLinkButton runat="server" NavigateUrl="~site/_layouts/recyclebin.aspx" ImageUrl="/_layouts/images/recycbin.gif" Text="<%$Resources:wss,StsDefault_RecycleBin%>" PermissionsString="DeleteListItems"/>
</td></tr>
</table>
</td></tr></table>
</div>
</div>
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder runat="server"></asp:ContentPlaceHolder>
</td>
</tr>
<tr><td colspan=2><asp:ContentPlaceHolder runat="server"><IMG SRC="/_layouts/images/blank.gif" width=138 height=1 alt=""></asp:ContentPlaceholder></td></tr>
</TABLE></td><td><asp:ContentPlaceHolder runat="server"></asp:ContentPlaceHolder></td>
</tr></table></TD>
<td><asp:ContentPlaceHolder runat="server"><div><IMG SRC="/_layouts/images/blank.gif" width=10 height=1 alt=""></div></asp:ContentPlaceHolder></td>
<td class='ms-bodyareacell' valign="top">
<table width=100% height="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td class='ms-bodyareaframe' valign="top" height="100%">
<A></A>
<asp:ContentPlaceHolder runat="server" />
<asp:ContentPlaceHolder runat="server" />
</td>
</tr>
</table>
</td>
<td><asp:ContentPlaceHolder runat="server">
<div><IMG SRC="/_layouts/images/blank.gif" width=10 height=1 alt=""></div>
</asp:ContentPlaceHolder></td>
</TR>
<tr>
<td><IMG SRC="/_layouts/images/blank.gif" width=1 height=10 alt=""></td>
<td><IMG SRC="/_layouts/images/blank.gif" width=1 height=10 alt=""></td>
<td><IMG SRC="/_layouts/images/blank.gif" width=1 height=10 alt=""></td>
<td><IMG SRC="/_layouts/images/blank.gif" width=1 height=10 alt=""></td>
</tr>
</TABLE>
<asp:ContentPlaceHolder runat="server" />
<asp:ContentPlaceHolder runat="server" />
</TD></TR>
</asp:ContentPlaceHolder>
<tr >
<td valign="top">
<table width="100%">
<tr>
<td>
<table>
<tr>
<td nowrap="nowrap"><b>YOUR LINKS HERE</b></td>
</tr>
</table>
</td>
<td width="100%" align="center" valign="middle">
</td>
<td valign="top" style="padding-left:3px; padding-right:20px;" nowrap="nowrap">
<b>Readers & Viewers</b><br />
<SharePoint:SPLinkButton Target="_new" ImageUrl="~site/_layouts/images/pdf.gif" runat="server" NavigateUrl="http://get.adobe.com/reader/" Text="PDF" PermissionsString="ViewPages"/>&nbsp;
<SharePoint:SPLinkButton Target="_new" ImageUrl="~site/_layouts/images/ppt.gif" runat="server" NavigateUrl="http://www.microsoft.com/downloads/details.aspx?FamilyId=428D5727-43AB-4F24-90B7-A94784AF71A4&displaylang=en" Text="PowerPoint" PermissionsString="ViewPages"/>&nbsp;
<SharePoint:SPLinkButton Target="_new" ImageUrl="~site/_layouts/images/zip.gif" runat="server" NavigateUrl="http://www.winzip.com/" Text="ZIP" PermissionsString="ViewPages"/>&nbsp;
<SharePoint:SPLinkButton Target="_new" ImageUrl="~site/_layouts/images/doc.gif" runat="server" NavigateUrl="http://www.microsoft.com/downloads/details.aspx?FamilyID=95e24c87-8732-48d5-8689-ab826e7b8fdf" Text="Word" PermissionsString="ViewPages"/>&nbsp;
<SharePoint:SPLinkButton Target="_new" ImageUrl="~site/_layouts/images/xls.gif" runat="server" NavigateUrl="http://www.microsoft.com/downloads/details.aspx?FamilyId=C8378BF4-996C-4569-B547-75EDBD03AAF0" Text="Excel" PermissionsString="ViewPages"/>
</td>
<td valign="top" nowrap="nowrap">
<b>
<SharePoint:SPLinkButton runat="server" NavigateUrl="~site/_layouts/YourPageHere.aspx" Text="Your Site Information" PermissionsString="ViewPages"/></b>
<br/>&nbsp;
</td>
</tr>
</table>
</td>
</tr>
<tr >
<td align="center">
<table style="background-image:url(YOUR-URL-TO-YOUR-WATERMARK.gif);background-position:center; background-repeat:no-repeat">
<tr>
<td align="center" valign="middle" style="padding-left:3px; padding-right:6px;">
YOUR DISCLAIMER TEXT
</td>
</tr>
</table>
</td>
</tr>
</table>
<asp:ContentPlaceHolder runat="server">
<SharePoint:FormDigest runat=server/>
</asp:ContentPlaceHolder>
<input style="display:none;" size=1/>
<input style="display:none;" size=1/>
<asp:ContentPlaceHolder runat="server">
</asp:ContentPlaceHolder>
</form>
</BODY>
</HTML>

CHILD MASTER PAGE

<%@ master masterpagefile="~masterurl/default.master" meta:progid="SharePoint.WebPartPage.Document" %>

<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls" Assembly="Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="PublishingNavigation" Namespace="Microsoft.SharePoint.Publishing.Navigation" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="wssuc" TagName="DesignModeConsole" src="~/_controltemplates/DesignModeConsole.ascx" %>
<%@ Register TagPrefix="PublishingVariations" TagName="VariationsLabelMenu" src="~/_controltemplates/VariationsLabelMenu.ascx" %>
<%@ Register Tagprefix="PublishingConsole" TagName="Console" src="~/_controltemplates/PublishingConsole.ascx" %>
<%@ Register TagPrefix="PublishingSiteAction" TagName="SiteActionMenu" src="~/_controltemplates/PublishingActionMenu.ascx" %>
<asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
<asp:ContentPlaceHolder runat="server" />
</asp:Content>
<asp:Content ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
<asp:ContentPlaceHolder runat="server" />
</asp:Content>
<asp:Content runat="server" contentplaceholderid="PlaceHolderMainBase">
<tr><td>
<table width=100% cellpadding=0 cellspacing=0 border=0><tr>
<td>
<SharePoint:SiteLogoImage LogoImageUrl="/_layouts/images/logo.jpg" runat="server"/></td>
<td width=100%>
<asp:ContentPlaceHolder runat="server">
<h1>
<SharePoint:SPLinkButton runat="server" NavigateUrl="~site/">
<SharePoint:ProjectProperty Property="Title" runat="server" />
</SharePoint:SPLinkButton>
</h1>
</asp:ContentPlaceHolder>
</td>
<td style="padding-top:8px;" valign=top>
<asp:ContentPlaceHolder runat="server">
<SharePoint:DelegateControl runat="server" ControlId="SmallSearchInputBox"/>
</asp:ContentPlaceHolder>
</td>
</tr>
</table>
</td>
</tr>
<TR>
<TD WIDTH=100%>
<asp:ContentPlaceHolder runat="server">
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
<td nowrap valign="middle"></td>
<td-banner width=99% nowrap>
<asp:ContentPlaceHolder runat="server">
<SharePoint:AspMenu
Runat="server"
DataSourceID="topSiteMap"
EnableViewState="false"
AccessKey="<%$Resources:wss,navigation_accesskey%>"
Orientation="Horizontal"
StaticDisplayLevels="2"
MaximumDynamicDisplayLevels="1"
DynamicHorizontalOffset="0"
StaticPopoutImageUrl="/_layouts/images/menudark.gif"
StaticPopoutImageTextFormatString=""
DynamicHoverStyle-BackColor="#CBE3F0"
SkipLinkText=""
StaticSubMenuIndent="0"
CssClass="ms-topNavContainer">
<StaticMenuStyle/>
<StaticMenuItemStyle CssClass="ms-topnav" ItemSpacing="0px"/>
<StaticSelectedStyle CssClass="ms-topnavselected" />
<StaticHoverStyle CssClass="ms-topNavHover" />
<DynamicMenuStyle BackColor="#F2F3F4" BorderColor="#A7B4CE" BorderWidth="1px"/>
<DynamicMenuItemStyle CssClass="ms-topNavFlyOuts"/>
<DynamicHoverStyle CssClass="ms-topNavFlyOutsHover"/>
<DynamicSelectedStyle CssClass="ms-topNavFlyOutsSelected"/>
</SharePoint:AspMenu>
<SharePoint:DelegateControl runat="server" ControlId="TopNavigationDataSource">
<Template_Controls>
<asp:SiteMapDataSource
ShowStartingNode="False"
SiteMapProvider="SPNavigationProvider"
runat="server"
StartingNodeUrl="sid:1002"/>
</Template_Controls>
</SharePoint:DelegateControl>
</asp:ContentPlaceHolder>
</td>
<td-banner>&nbsp;&nbsp;</td>
<td valign=bottom align=right style="position:relative;bottom:0;left:0;">
<table cellpadding=0 cellspacing=0 border=0>
<tr>
<td>
<table height=100% cellpadding=0 cellspacing=0>
<tr>
<td>
<SharePoint:SiteActions runat="server" AccessKey="<%$Resources:wss,tb_SiteActions_AK%>"
PrefixHtml="&lt;div&gt;&lt;div&gt;"
SuffixHtml="&lt;/div&gt;&lt;/div&gt;"
MenuNotVisibleHtml="&amp;nbsp;">
<CustomTemplate>
<SharePoint:FeatureMenuTemplate runat="server"
FeatureScope="Site"
Location="Microsoft.SharePoint.StandardMenu"
GroupId="SiteActions"
UseShortId="true"
>
<SharePoint:MenuItemTemplate runat="server"
Text="<%$Resources:wss,viewlsts_pagetitle_create%>"
Description="<%$Resources:wss,siteactions_createdescription%>"
ImageUrl="/_layouts/images/Actionscreate.gif"
MenuGroupId="100"
Sequence="100"
UseShortId="true"
ClientOnClickNavigateUrl="~site/_layouts/create.aspx"
PermissionsString="ManageLists, ManageSubwebs"
PermissionMode="Any" />
<SharePoint:MenuItemTemplate runat="server"
Text="<%$Resources:wss,siteactions_editpage%>"
Description="<%$Resources:wss,siteactions_editpagedescription%>"
ImageUrl="/_layouts/images/ActionsEditPage.gif"
MenuGroupId="100"
Sequence="200"
ClientOnClickNavigateUrl="javascript:MSOLayout_ChangeLayoutMode(false);"
/>
<SharePoint:MenuItemTemplate runat="server"
Text="<%$Resources:wss,settings_pagetitle%>"
Description="<%$Resources:wss,siteactions_sitesettingsdescription%>"
ImageUrl="/_layouts/images/ActionsSettings.gif"
MenuGroupId="100"
Sequence="300"
UseShortId="true"
ClientOnClickNavigateUrl="~site/_layouts/settings.aspx"
PermissionsString="EnumeratePermissions,ManageWeb,ManageSubwebs,AddAndCustomizePages,ApplyThemeAndBorder,ManageAlerts,ManageLists,ViewUsageData"
PermissionMode="Any" />
</SharePoint:FeatureMenuTemplate>
</CustomTemplate>
</SharePoint:SiteActions>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</asp:ContentPlaceHolder>
</TD>
</TR>
<asp:ContentPlaceHolder runat="server">
<wssuc:DesignModeConsole runat="server"/>
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder runat="server">
<SharePoint:DelegateControl runat="server" ControlId="PublishingConsole"
PrefixHtml="&lt;tr&gt;&lt;td colspan=&quot;4&quot; id=&quot;mpdmconsole&quot; class=&quot;ms-consolemptablerow&quot;&gt;"
SuffixHtml="&lt;/td&gt;&lt;/tr&gt;">
</SharePoint:DelegateControl>
</asp:ContentPlaceHolder>
<TR height="100%"><TD><TABLE width="100%" height="100%" cellspacing="0" cellpadding="0">
<tr>
<td valign="middle" nowrap><div style="height:100%"><asp:ContentPlaceHolder runat="server"/></div></td>
<td>
<asp:ContentPlaceHolder runat="server">
<div><IMG SRC="/_layouts/images/blank.gif" width=1 height=100% alt=""></div>
</asp:ContentPlaceHolder>
</td>
<td valign=top class='ms-pagetitleareaframe' nowrap>
<table cellpadding=0 cellspacing=0 width=100% border="0">
<tr>
<td valign="top">
<asp:ContentPlaceHolder runat="server">
<asp:SiteMapPath SiteMapProvider="SPContentMapProvider" SkipLinkText="" NodeStyle-CssClass="ms-sitemapdirectional" runat="server"/> &nbsp;
</asp:ContentPlaceHolder>
</td>
</tr>
<tr>
<td height=100% valign=top>
<h2>
<asp:ContentPlaceHolder runat="server" />
</h2>
</td>
</tr>
</table>
</td>
<td>
<asp:ContentPlaceHolder runat="server"/>
<asp:ContentPlaceHolder runat="server">
<div style='height:100%'><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></div>
</asp:ContentPlaceHolder></td>
</tr>
<asp:ContentPlaceHolder runat="server"/>
<TR>
<TD valign=top height=100%>
<table-nav width=100% height=100% cellpadding=0 cellspacing=0>
<tr>
<td>
<TABLE height="100%"-navframe CELLPADDING=0 CELLSPACING=0 border="0">
<tr valign="top">
<td width="4px"><IMG SRC="/_layouts/images/blank.gif" width=4 height=1 alt=""></td>
<td valign="top" width="100%">
<asp:ContentPlaceHolder runat="server" />
<asp:ContentPlaceHolder runat="server" />
<asp:ContentPlaceHolder runat="server"/>
<asp:ContentPlaceHolder runat="server">
<div>
<div style="width:100%">
<h3><label>
<SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,quiklnch_pagetitle%>" EncodeMethod="HtmlEncode"/></label>
<Sharepoint:SPSecurityTrimmedControl runat="server" PermissionsString="ViewFormPages">
<div><SharePoint:SPLinkButton runat="server" NavigateUrl="~site/_layouts/viewlsts.aspx" Text="<%$Resources:wss,quiklnch_allcontent%>" AccessKey="<%$Resources:wss,quiklnch_allcontent_AK%>"/></div>
</SharePoint:SPSecurityTrimmedControl>
</h3>
<Sharepoint:SPNavigationManager
runat="server"
QuickLaunchControlId="QuickLaunchMenu"
ContainedControl="QuickLaunch"
EnableViewState="false">
<div>
<SharePoint:DelegateControl runat="server"
ControlId="QuickLaunchDataSource">
<Template_Controls>
<asp:SiteMapDataSource
SiteMapProvider="SPNavigationProvider"
ShowStartingNode="False"
StartingNodeUrl="sid:1025"
runat="server"
/>
</Template_Controls>
</SharePoint:DelegateControl>
<SharePoint:AspMenu
DataSourceId="QuickLaunchSiteMap"
runat="server"
Orientation="Vertical"
StaticDisplayLevels="2"
ItemWrap="true"
MaximumDynamicDisplayLevels="0"
StaticSubMenuIndent="0"
SkipLinkText=""
>
<LevelMenuItemStyles>
<asp:MenuItemStyle CssClass="ms-navheader"/>
<asp:MenuItemStyle CssClass="ms-navitem"/>
</LevelMenuItemStyles>
<LevelSubMenuStyles>
<asp:SubMenuStyle CssClass="ms-navSubMenu1"/>
<asp:SubMenuStyle CssClass="ms-navSubMenu2"/>
</LevelSubMenuStyles>
<LevelSelectedStyles>
<asp:MenuItemStyle CssClass="ms-selectednavheader"/>
<asp:MenuItemStyle CssClass="ms-selectednav"/>
</LevelSelectedStyles>
</SharePoint:AspMenu>
</div>
</Sharepoint:SPNavigationManager>
<Sharepoint:SPNavigationManager
runat="server"
ContainedControl="TreeView">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td nowrap>
<SharePoint:SPLinkButton runat="server" NavigateUrl="~site/_layouts/viewlsts.aspx" Text="<%$Resources:wss,treeview_header%>" AccessKey="<%$Resources:wss,quiklnch_allcontent_AK%>"/>
</td>
</tr>
</table>
</td>
</tr>
</table>
<div>
<SharePoint:SPHierarchyDataSourceControl
runat="server"
RootContextObject="Web"
IncludeDiscussionFolders="true"
/>
<SharePoint:SPRememberScroll runat="server" Style="overflow: auto;height: 400px;width: 150px; ">
<Sharepoint:SPTreeView
runat="server"
ShowLines="false"
DataSourceId="TreeViewDataSource"
ExpandDepth="0"
SelectedNodeStyle-CssClass="ms-tvselected"
NodeStyle-CssClass="ms-navitem"
NodeStyle-HorizontalPadding="2"
SkipLinkText=""
NodeIndent="12"
ExpandImageUrl="/_layouts/images/tvplus.gif"
CollapseImageUrl="/_layouts/images/tvminus.gif"
NoExpandImageUrl="/_layouts/images/tvblank.gif"
>
</Sharepoint:SPTreeView>
</Sharepoint:SPRememberScroll>
</div>
</Sharepoint:SPNavigationManager>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tr><td>
<table width="100%" cellpadding="0" cellspacing="0" border="0">
<tr><td nowrap>
<SharePoint:SPLinkButton runat="server" NavigateUrl="~site/_layouts/recyclebin.aspx" ImageUrl="/_layouts/images/recycbin.gif" Text="<%$Resources:wss,StsDefault_RecycleBin%>" PermissionsString="DeleteListItems"/>
</td></tr>
</table>
</td></tr></table>
</div>
</div>
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder runat="server"></asp:ContentPlaceHolder>
</td>
</tr>
<tr><td colspan=2><asp:ContentPlaceHolder runat="server"><IMG SRC="/_layouts/images/blank.gif" width=138 height=1 alt=""></asp:ContentPlaceholder></td></tr>
</TABLE></td><td><asp:ContentPlaceHolder runat="server"></asp:ContentPlaceHolder></td>
</tr></table></TD>
<td><asp:ContentPlaceHolder runat="server"><div><IMG SRC="/_layouts/images/blank.gif" width=10 height=1 alt=""></div></asp:ContentPlaceHolder></td>
<td class='ms-bodyareacell' valign="top">
<table width=100% height="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td class='ms-bodyareaframe' valign="top" height="100%">
<A></A>
<asp:ContentPlaceHolder runat="server" />
<asp:ContentPlaceHolder runat="server" />
</td>
</tr>
</table>
</td>
<td><asp:ContentPlaceHolder runat="server">
<div><IMG SRC="/_layouts/images/blank.gif" width=10 height=1 alt=""></div>
</asp:ContentPlaceHolder></td>
</TR>
<tr>
<td><IMG SRC="/_layouts/images/blank.gif" width=1 height=10 alt=""></td>
<td><IMG SRC="/_layouts/images/blank.gif" width=1 height=10 alt=""></td>
<td><IMG SRC="/_layouts/images/blank.gif" width=1 height=10 alt=""></td>
<td><IMG SRC="/_layouts/images/blank.gif" width=1 height=10 alt=""></td>
</tr>
</TABLE>
<asp:ContentPlaceHolder runat="server" />
<asp:ContentPlaceHolder runat="server" />
</TD></TR>
</asp:Content>

customURLtoUseCHILD = web.ServerRelativeUrl + customizedMasterUrlCHILD;
customURLtoUseCHILD = customURLtoUseCHILD.Replace(“//”, “/”);
// Store the old Master URL’s and Custom Master URL’s
web.AllProperties[“OldMasterUrl”] = web.MasterUrl;
web.AllProperties[“OldCustomMasterUrl”] = web.CustomMasterUrl;
// Assign the Master URL to both properties
web.MasterUrl = customURLtoUsePARENT;
web.CustomMasterUrl = customURLtoUseCHILD;
// Update the Web
web.Update();
}
}
catch { }
}
You may also wish to remove BOTH files in the FeatureDeactivating function.
Finally, instead of stapling the feature to GLOBAL, we need to specify the templates. Namely, all of them except for the Meeting Workspaces templates. This is due to a SharePoint bug where if you create a meeting workspace from a recurring Calendar event, if you try to staple a feature to the new meeting workspace site, it breaks the scripting on the page such that you cannot switch dates.
<elements xmlns="http://schemas.microsoft.com/sharepoint/">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="STS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="STS#1">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="STS#2">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="WIKI#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLOG#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BDR#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="EAWF#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="OFFILE#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="OFFILE#1">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="PWA#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="PWS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSMSITE#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSTOC#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSTOPIC#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSNEWS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSNHOME#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSSITES#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSBWEB#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSCOMMU#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSREPORTCENTER#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSPORTAL#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SRCHCEN#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="PROFILES#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="CMSPUBLISHING#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLANKINTERNET#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLANKINTERNET#1">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLANKINTERNET#2">
</elements>

 

customURLtoUsePARENT = web.ServerRelativeUrl + customizedMasterUrlPARENT;
customURLtoUsePARENT = customURLtoUsePARENT.Replace(“//”, “/”);
// Store the old Master URL’s and Custom Master URL’s
web.AllProperties[“OldMasterUrl”] = web.MasterUrl;
web.AllProperties[“OldCustomMasterUrl”] = web.CustomMasterUrl;
// Assign the Master URL to both properties
web.MasterUrl = customURLtoUsePARENT;
web.CustomMasterUrl = customURLtoUseCHILD;
// Update the Web
web.Update();
}
}
catch { }
}
You may also wish to remove BOTH files in the FeatureDeactivating function.
Finally, instead of stapling the feature to GLOBAL, we need to specify the templates. Namely, all of them except for the Meeting Workspaces templates. This is due to a SharePoint bug where if you create a meeting workspace from a recurring Calendar event, if you try to staple a feature to the new meeting workspace site, it breaks the scripting on the page such that you cannot switch dates.
<elements xmlns="http://schemas.microsoft.com/sharepoint/">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="STS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="STS#1">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="STS#2">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="WIKI#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLOG#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BDR#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="EAWF#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="OFFILE#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="OFFILE#1">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="PWA#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="PWS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSMSITE#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSTOC#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSTOPIC#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSNEWS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSNHOME#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSSITES#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSBWEB#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSCOMMU#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSREPORTCENTER#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSPORTAL#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SRCHCEN#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="PROFILES#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="CMSPUBLISHING#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLANKINTERNET#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLANKINTERNET#1">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLANKINTERNET#2">
</elements>

 

MOSS – Global Custom Master Template

Objective

The Problem

Let’s say you want to force your entire organization to use your custom master page. You may wish to have certain contact information, legal disclaimers, utilities, or other functionality on your page that is standard company-wide. The problem we face is how to get this feature automatically activated on each and every site, of every type, when newly created.

The Solution

We will create 2 features – one to install the Custom Master Page into the Master Page Gallery of each site, as well as activate that page as the currently used master page; and one feature, called “Feature Stapling”, to have that first feature automatically activate.

References

The code in this article is taken in large part from other articles out there in blogLand – PLEASE at least skim over these articles to see the similarities and differences to this post. Also, there is a lot more explanation of the code itself (what it does) in Becky Bertram’s article.

Why is this Different from the first referenced article?

It isn’t all that much different from Becky Bertram’s code – let me please give credit where due. However, I found that in some circumstances the URL to the custom master page did not work; and most importantly, this only worked for Sub Sites already added to the Site Collection. I wanted to get a feature which activated on each and every NEW site and site collection. As for the existing sites, well, we’ll just use CorasWorks Design Migrator to push out the master page to those sites.

Alternatively, once the feature is installed, you can activate it on every existing site. If you don’t want to do this on every site, and just want to do this for a site collection down, then take Becky Bertram’s original code with the ProcessSubWebs method which pushes the changes to every child.

Finally, I wanted to write an article that not only had the code, but also the complete steps to create the solution package, which I find is not all that intuitive if you’re not used to it. For the second feature, we won’t even bother to create a solution – we’ll just use the elements and feature files in a folder and run an stsadm command line on them.

Danger

A word of warning – test your master page thoroughly before turning on these features. You could potentially break every page in your site if you’re not careful. Always keep the url /_layouts/settings.aspx in handy reach in case you get an error on the page and need to go back to turn the feature off. Sometimes you will get a “File Not Found” or other error if the custom URL path is off, and you can’t even navigate around the regular pages of the site.

Also, NEVER MESS WITH default.master IN THE 12 HIVE GLOBAL DIRECTORY.  Service packs will overwrite your changes.

FEATURE # 1 – Master Page with Feature Receiver

Install WSPBuilder
Create the Visual Studio Project
  • File à New à Project
  • WSPBuilder à WSPBuilder Project
  • Under the 12 folder, create a folder named Template
  • Under the Template folder, create a folder named Features
  • Under the Features folder, create a folder named YourCompanyCustomMaster
  • Under the YourCompanyCustomMaster folder, create a folder named MasterPages
  • Under the YourCompanyCustomMaster folder, create a file named feature.xml
  • Under the YourCompanyCustomMaster folder, create a file named elements.xml
  • Under the MasterPages folder, create a master page file named YourCompanyCustomMaster.master
  • Under the root of your project, create a code file named FeatureReceiver.cs.
  • Your project should now resemble the following:
     

    • File Structure

      File Structure

      Paste the code from below into the Feature.xml File, the Elements.xml file, and the FeatureReceiver.cs file.

    • Create a new Guid for your Feature ID (In Visual Studio, choose Tools à Create GUID) and paste it in to the Feature ID. Be sure to remove any { } braces from the guid, such that the end result resembles: Id=F647BBF6-5277-4118-9FA8-87D3E7C2059C“.  NOTE: The ID you create here is the ID you will use in the elements file in the second feature.
    • In order to get a Public Key for the Receiver Assembly, temporarily register this file into your GAC. I find the easiest way to do this is to open up C:\Windows\Assembly and just drag the file in. Then right-click on the file and choose Properties. You can copy the public key token right from the message box. The project has to have a key file associated with it to be registered into the GAC, but WSPBuilder already did that for you.
       

      Assembly Key

      Assembly Key

    • Compile your code. Right-click on the project and choose WSPBuilder à Build WSP. This builds the WSP file and places it in the root directory.
       

      Build WSP

      Build WSP

    • If you are developing on your Development SharePoint machine, or your Production Machine (although I would NOT recommend deploying this straight into production), you can use the WSPBuilder command “Deploy” (see above picture) to move the WSP file into the SharePoint environment. If you do not have WSPBuilder, or you are not on your SharePoint box, then copy the WSP file over to the SharePoint machine and run the following commands from STSADM (Typically located in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\BIN)
          stsadm -o addsolution -filename <file_path>\YourCompanyCustomMaster.wsp, where <file_path> is the location of your wsp file
          stsadm -o deploysolution -name YourCompanyCustomMaster.wsp -allowgacdeployment
Feature File

<Feature Id=<a new guid> Title=YourCompany Custom Master Page
   Scope=Web Version=1.0.0.0 Hidden=FALSE DefaultResourceFile=core
   xmlns=http://schemas.microsoft.com/sharepoint/
   Description
=This Feature contains the YourCompany’s Custom Master Page
   ReceiverAssembly=YourCompanyCustomMaster, Version=1.0.0.0, Culture=neutral,     
      PublicKeyToken=<your public key>

   ReceiverClass=YourCompanyCustomMaster.FeatureReceiver>
   <ElementManifests>
      <ElementManifest Location=elements.xml />
      <ElementFile Location=MasterPages\YourCompanyCustomMaster.master />
   </ElementManifests>
</Feature>

Elements File

<Elements xmlns=http://schemas.microsoft.com/sharepoint/>
   <Module Name=YourCompanyCustomMaster Url=_catalogs/masterpage Path=MasterPages
      RootWebOnly
=TRUE

      <File Url=YourCompanyCustomMaster.master Name=YourCompanyCustomMaster.master
         Type
=GhostableInLibrary >

         <Property Name=ContentType
            Value
=$Resources:cmscore,contenttype_masterpage_name; />

      </File>
   </Module>
</Elements>  

Feature Receiver

using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
 
namespace YourCompanyCustomMaster
{
   public class FeatureReceiver : SPFeatureReceiver
   {
      // Code adapted from:
      // http://www.beckybertram.com/oldblog/index.php?p=33&more=1&c=1&tb=1&pb=1
 
      // Master Page Feature adapted from:
      // http://sharepointmagazine.net/technical/development/deploying-the-master-page
 
      const string defaultMasterUrl = “/_catalogs/masterpage/default.master”;
      const string customizedMasterUrl = “/_catalogs/masterpage/AKGCustomMaster.master”;
 
      public override void FeatureInstalled(SPFeatureReceiverProperties properties) { }
 
      public override void FeatureUninstalling(SPFeatureReceiverProperties properties) { }
 
      public override void FeatureActivated(SPFeatureReceiverProperties properties)
      {
         try
         {
            using (SPWeb web = (SPWeb)properties.Feature.Parent)
            {
               string customURLtoUse = customizedMasterUrl;
 
               customURLtoUse = web.ServerRelativeUrl + customizedMasterUrl;
               customURLtoUse = customURLtoUse.Replace(“//”, “/”);
 
               // Store the old Master URL’s and Custom Master URL’s
               web.AllProperties[“OldMasterUrl”] = web.MasterUrl; 
               web.AllProperties[“OldCustomMasterUrl”] = web.CustomMasterUrl; 
 
               // Assign the Master URL to both properties
               web.MasterUrl = customURLtoUse;
               web.CustomMasterUrl = customURLtoUse;
 
               // Update the Web
               web.Update(); 
            } 
         }
         catch { } 
      }
 
      private void DeactivateWeb(SPWeb web)
      {
         try
         {
            if (web.AllProperties.ContainsKey(“OldMasterUrl”))
            {
               // Change the MasterURL and CustomMasterURL back to
               // old versions, if the property exists
               string oldMasterUrl = web.AllProperties[“OldMasterUrl”].ToString();
               try
               { 
                  bool fileExists = web.GetFile(oldMasterUrl).Exists;
                  web.MasterUrl = oldMasterUrl;
               }
               catch (ArgumentException)
               {
                  web.MasterUrl = defaultMasterUrl;
               }
 
               string oldCustomUrl = web.AllProperties[“OldCustomMasterUrl”].ToString();
               try
               {
                  bool fileExists = web.GetFile(oldCustomUrl).Exists;
                  web.CustomMasterUrl = web.AllProperties[“OldCustomMasterUrl”].ToString();
               }
               catch (ArgumentException)
               {
                  web.CustomMasterUrl = defaultMasterUrl;
               }
 
               // Remove the custom properties
               web.AllProperties.Remove(“OldMasterUrl”);
               web.AllProperties.Remove(“OldCustomMasterUrl”); 
            } 
            else
            {
               // Otherwise, change back to default
               web.MasterUrl = defaultMasterUrl;
               web.CustomMasterUrl = defaultMasterUrl;
            } 
         }
         catch
         {
            try
            {
               web.MasterUrl = defaultMasterUrl;
               web.CustomMasterUrl = defaultMasterUrl;
            } 
            catch { }
         }
      }
 
      public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
      {
         try
         {
            using (SPWeb web = (SPWeb)properties.Feature.Parent)
            {
               DeactivateWeb(web);
               web.Update(); 
 
               string customURLtoUse = web.ServerRelativeUrl + customizedMasterUrl;
               customURLtoUse = customURLtoUse.Replace(“//”, “/”);
 
               // Delete the file manually from the master page gallery
               if (web.MasterUrl != customURLtoUse)
               {
                  try
                  {
                     bool fileExists = web.GetFile(customURLtoUse).Exists;
                     SPFile file = web.GetFile(customURLtoUse);
                     SPFolder masterPageGallery = file.ParentFolder; 
  
                     // Unfortunately, there seems to be an issue in SharePoint where 
                     // you can not delete a master page that was installed by a
                     // feature, even if no one is referencing that master page.
                     // You have to move it to another folder then delete that folder. 
                     SPFolder temp = masterPageGallery.SubFolders.Add(“Temp”);
                     file.MoveTo(temp.Url + “/” + file.Name);
                     temp.Delete(); 
                  }
                  catch (ArgumentException)
                  {
                     return;
                  } 
               } 
            } 
         }
         catch { } 
      }
   }
}
 

FEATURE # 2 – Stapling the first feature to every new web

What is Feature Stapling?

A basic explanation of feature stapling is that it is used to attach one or more features to a SharePoint site definition without modifying an existing site definition or creating a new site definition. For a more detailed explanation I recommend reading Chris Jonson’s blog on “Feature Stapling in WSS V3”.

Create the files in the Feature folder

For this exercise, we will not even bother creating a solution through Visual Studio. Let’s just put the simple files directly into a Feature Folder on the 12 hive and add the solution.

  • Navigate to the 12 hive, usually at C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\FEATURES.
  • Create a new folder, and name it YourCompanyMasterStapling.
  • In the YourCompanyMasterStapling folder, create 2 files – elements.xml and feature.xml.
  • Paste the code from below into the Feature.xml File, and the Elements.xml file.
  • Create a new Guid for your Feature ID (In Visual Studio, choose Tools à Create GUID) and paste it in to the Feature ID. Be sure to remove any { } braces from the guid, such that the end result resembles: Id=F647BBF6-5277-4118-9FA8-87D3E7C2059D“.  NOTE: The ID you create here is NOT the ID you’re using in the Elements file – rather use the Feature ID from the FIRST feature.
  • Run the following commands from STSADM (Typically located in C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\BIN)
        stsadm -o installfeature -filename YourCompanyMasterStapling\feature.xml
        stsadm -o activatefeature -filename YourCompanyMasterStapling\feature.xml
  • NOTE: You may receive a message stating that the feature has already been activated to the farm.
Feature File

<?xml version=1.0 encoding=utf-8 ?>
<Feature Id=<a new guid>
   Title=YourCompany Custom Master Page Feature Stapling
   Description=YourCompany Custom Master Page Feature Stapling – activates the YourCompany
      Master Page feature for all new sites

   Version=1.0.0.0
   Scope=Farm
   Hidden=TRUE
   xmlns=http://schemas.microsoft.com/sharepoint/
   <ElementManifests>
      <ElementManifest Location=elements.xml/>
   </ElementManifests
</Feature>

Elements File

<Elements xmlns=http://schemas.microsoft.com/sharepoint/>
    <FeatureSiteTemplateAssociation Id=<the guid from feature 1> TemplateName=GLOBAL /> ** Read update below
</Elements>

UPDATE:  Do not use GLOBAL – there is a bug:   if you create a meeting workspace from a recurring Calendar event, if you try to staple a feature to the new meeting workspace site, it breaks the scripting on the page such that you cannot switch dates.  Instead staple to all templates EXCEPT Meeting Workspaces:

<elements xmlns="http://schemas.microsoft.com/sharepoint/">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="STS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="STS#1">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="STS#2">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="WIKI#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLOG#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BDR#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="EAWF#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="OFFILE#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="OFFILE#1">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="PWA#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="PWS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSMSITE#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSTOC#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSTOPIC#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSNEWS#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSNHOME#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSSITES#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSBWEB#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSCOMMU#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSREPORTCENTER#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SPSPORTAL#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="SRCHCEN#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="PROFILES#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="CMSPUBLISHING#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLANKINTERNET#0">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLANKINTERNET#1">
<featuresitetemplateassociation id="F647BBF6-5277-4118-9FA8-87D3E7C2059C" templatename="BLANKINTERNET#2">
</elements>

 

Testing

Make sure you test your creation thoroughly. Test the following areas:

Root Web Site

The Root Web of the Root site – typically the portal site (the one without “sites” in the url).

Site Collections

Create a new Site Collection and check its Root Web.

Sub Sites

Create and test each type of Sub Site – create a Team Site, a Blog Site, a Meeting Workspace, a Publishing Portal, and a Document Center Portal at the very least