One thing we like to do on most of our projects is create a version control and deployment system that allows us to keep everyone on the team in sync. This is important because almost every team will have several people who are contributing content, design elements, and requirements who are not developers, in fact these people usually account for the majority. Just the same, we need a way to isolate the work of each to avoid lost productivity that comes about when people try to share an environment for a new project that is changing rapidly.
The thing that makes the process work is that one person, usually the architect (me), or a small team receives deliverables (Visual Studio bits, pages exported from SharePoint Designer, graphics, CSS, etc.) from each person and integrates it into a solution. Then when each person is ready, they run a script that recreates their environment from a set of solution packages. We expect each person to do this very regularly - each time they turn over something for integration. One or more of these packages will have feature(s) that are basically provisioning scripts to create sub-sites, configure security, and configure navigation. I must say it works pretty well and makes the project easy to run by both minimizing the aforementioned productivity losses and also running each deliverable through a funnel where we can continuously check the quality and adherence to requirements.
When we're doing development on WSS instead of MOSS (which accounts for the vast majority of our work) the scripts are different because WSS lacks the Microsoft.SharePoint.Publishing assembly that has a large number of classes that make things pretty easy. Today I spent some time for the third or fourth time in the last couple of years relearning how it's done with nothing but Microsoft.SharePoint. This time I made a more generalized solution and I am posting it here so I can find it later. J
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
//This is a site scoped feature, the root web is created in a cmd script.
SPSite site = (SPSite)properties.Feature.Parent;
SPWeb rootWeb = site.RootWeb;
//Make subsite as a Blank team site
SPWeb subWeb =
rootWeb.Webs.Add("SubWeb", "Sub Web",
"A meaningful description", 1033, "STS#1", false, false);
//Add the new site to the top navigation bar and the quick launch menu
SetNavigation(subWeb);
}
public void SetNavigation(SPWeb web)
{
//Share navigation with the parent web
web.Navigation.UseShared = true;
//Try to get the top navigation bar
SPNavigationNodeCollection topNavigationBar = null;
topNavigationBar = web.ParentWeb.Navigation.TopNavigationBar;
//If found, add the new web at the end
if (topNavigationBar != null)
{
SPNavigationNode topNode = CreateHomeNode(web, web.Title);
try
{
topNavigationBar.AddAsLast(topNode);
}
catch (SPException)
{
}
}
//Try to find the Sites node on the
//parent web's quick launch
SPNavigationNode sitesNode =
GetNodeFromTitle("Sites", web.ParentWeb.Navigation.QuickLaunch);
//If found, add the new web at the end
if (sitesNode != null)
{
SPNavigationNode leftNode = CreateHomeNode(web, web.Title);
try
{
sitesNode.Children.AddAsLast(leftNode);
}
catch (SPException)
{
}
}
web.Update();
}
//Iterate a navigation node collection
//and return the node with a given title if any
private SPNavigationNode GetNodeFromTitle(string title,
SPNavigationNodeCollection nodes)
{
for (int i = 0; i < nodes.Count; i++)
{
if (nodes[ i].Title == title)
{
return nodes[ i];
}
}
return null;
}
//Create a navigation node for a given web's welcome page
private SPNavigationNode CreateHomeNode(SPWeb web, string nodeTitle)
{
if (string.IsNullOrEmpty(nodeTitle))
{
nodeTitle = web.Title;
}
string welcomePage = web.RootFolder.WelcomePage;
if (string.IsNullOrEmpty(welcomePage))
{
welcomePage = "default.aspx";
}
return new SPNavigationNode(nodeTitle,
web.ServerRelativeUrl + "/" + welcomePage);
}