Creating web templates from sites using SharePoint 2010 and Visual Studio 2010 is a fairly straightforward process, so long as you don’t try to do it with a site that has publishing enabled. The basic steps are:
- Save your site as a template with content included (Site Actions –> Site Settings –> Save Site as Template)
- Download the saved template from the template gallery
- In Visual Studio 2010, create a new project of type “Import SharePoint Solution Package
- Run through the wizard, selecting your saved template as the wsp file when prompted.
- Right click / Deploy
By default, that will create a sandboxed solution that you can then use to create sites within the site collection where the solution was deployed. With two simple changes, you can make it a farm solution that can then be used to create new site collections as well:
- Change the Visual Studio solution to a farm solution – either chose Farm solution when creating the project or set the project’s Sandboxed Solution property to False after the project has been created
- Change the scope of the Web Template Feature (Feature3 by default) to Farm.
Now, your deployed web template will show up in the site template gallery when creating any site or site collection.
Now, what if you want to perform this on a site with publishing enabled? You’ll hit several road blocks…
What do you mean publishing enabled?
First things first – to enable publishing on a site, you need to enable two features, one on the site collection, and one on the web. At the site collection scope (Site Actions –> Site Settings –> Site Collection Features), enable the SharePoint Server Publishing Infrastructure feature. At the web scope (Site Actions –> Site Settings –> Manage Site Features), enable the SharePoint Server Publishing feature.
At this point, modify the site the way you would like it to be for new sites based on the web template. That can include a custom master page, custom page layouts, new publishing pages, web parts, custom content types – anything that you want will (in theory) be included in your web template project.
Roadblock 1: Where did Save site as template go?
The first thing you’ll notice when you go to save your template is that the option for saving the site as a template is no longer there – it gets removed when you enable publishing. There may be a good reason for this – in MOSS for example, you ran the risk of a template getting deployed in another site collection not necessarily having all the content types you would need for the template to work properly. With Web Templates, though, it appears all that content gets stored with the template, so I’m not sure why the feature has been removed.
Before publishing is enabled:
After publishing is enabled:
There are several ways around this, including writing a feature to re-enable this option on the site settings page, but the easiest thing to do is just enter
Be sure to click “include content” so everything gets loaded into your SharePoint solution, including content types.
Once the template is created, click on the solution gallery link and save the template’s WSP file to your local disk.
Now go to Visual Studio and create a new project. The type will be “Import SharePoint Solution Package”. Give it a name and click OK.
When prompted for a deployment site, enter a site that you don’t care about. I would create a fresh site collection just for this purpose – the deployment will likely overwrite whatever is there.
Next, browse to your saved template file. Click Next.
Visual studio will then show you all the things it is about to import from your WSP file. You may be tempted to de-select some of the content, but if you do you’re likely to create errors in your solution that will need to be resolved, and the likely resolution will be to add the content back. Just leave everything selected and click finish.
Since we made this a Farm solution, we’ll need to modify the scope of the Web Template feature. For my publishing enabled team site, this is Feature 3:
You now have a visual studio project that is ready to be deployed and used to create new sites. Or so it would seem…
Roadblock 2: deployment error.
Project –> Right Click –> Deploy. Visual studio will alert you to many deployment conflicts – just let it resolve them automatically. You’re deploying to a site you don’t care about, remember?
There will be a lot of errors where SharePoint was unable to delete items to resolve conflicts. Most likely, the definition in the web template is a match for what already exists in SharePoint, namely standard list instances and content types. Nothing to worry about.
What you do need to worry about is the error message after the conflicts are “resolved”:
Error occurred in deployment step ‘Add Solution’: Dependency feature ‘PublishingSite’ (id: f6924d36-2fa8-4f0b-b16d-06b7250180fa) is not properly scoped for feature ‘PublishingWebTemplate_Feature3′ (id: 6fd24c8e-b684-42ab-9bbf-56759dfd5ea2). Its scope ‘Site’ must be equal to or higher than ‘Farm’.
For some reason, when the WSP file was imported and Feature3 was generated, Visual Studio decided to make the SharePoint publishing site a dependency. This really makes no sense because the onet.xml file that was created will activate this feature, so there’s no reason for it to be a dependency.
To remove the dependency, double click Feature 3 to load the feature designer, scroll down to the bottom and expand “Feature Activation Dependencies, scroll down again, select the dependency and click “Remove”.
Now that that’s out of the way, right click-deploy again, and you will run into…
Roadblock 3: Deployment Error HRESULT: 0×80070002
File not found. This one has to be a bug. When you deploy, your error list look like this:
The warning was mentioned previously – Visual Studio couldn’t resolve all the conflicts. Again, no big deal. The problem is the error. Here, the output window offers no help.
Deployment conflict resolution for one or more items failed. See the Output Window for details.
Adding solution ‘PublishingWebTemplate.wsp’…
Deploying solution ‘PublishingWebTemplate.wsp’…
Activating feature ‘Feature1′ …
Error occurred in deployment step ‘Activate Features’: The system cannot find the file specified. (Exception from HRESULT: 0×80070002)
========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
========== Deploy: 0 succeeded, 1 failed, 0 skipped ==========
It took me a while to figure out exactly what is causing this. The answer is included in the SharePoint ULS log files:
Cannot find doc C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions14TemplateFeaturesPublishingWebTemplate_Feature1FilesVariation LabelsAllItems.aspx
Failed to add list view and form pages for list "Variation Labels" in web "http://homedev/sites/test". hr = 0x2ecf41d0
Failed to create list "Variation Labels" in web "http://homedev/sites/test", HRESULT=0x2ecf41d0. List XML: "
Failed to instantiate list ‘C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions14TemplateFeaturesCustomListcustlist’
Unknown SPRequest error occurred. More information: 0×80070002
Leaving Monitored Scope (List Creation: Variation Labels). Execution Time=70.0444709826517
The element of type ‘ListInstance’ for feature ‘PublishingWebTemplate_Feature1′ (id: 14a09d46-89fb-4c97-bc3e-7797944b23d8) threw an exception during activation: The system cannot find the file specified. (Exception from HRESULT: 0×80070002)
Feature Activation: Threw an exception, attempting to roll back. Feature ‘PublishingWebTemplate_Feature1′ (ID: ’14a09d46-89fb-4c97-bc3e-7797944b23d8′). Exception: System.IO.FileNotFoundException: The system cannot find the file specified. (Exception from HRESULT: 0×80070002) at Microsoft.SharePoint.Administration.SPElementDefinitionCollection.ProvisionListInstances(SPFeaturePropertyCollection props, SPSite site, SPWeb web, Boolean fForce) at Microsoft.SharePoint.Administration.SPElementDefinitionCollection.ProvisionElements(SPFeaturePropertyCollection props, SPWebApplication webapp, SPSite site, SPWeb web, Boolean fForce) at Microsoft.SharePoint.SPFeature.Activate(SPSite siteParent, SPWeb webParent, SPFeaturePropertyCollection props, Boolean fForce)
Even armed with this information, it isn’t clear what needs to be done to resolve the issue.
Here’s what you need to do:
- Expand “Other Imported Files
- Copy “AllItems.aspx” to “List InstancesVariation_Labels”
- On the copied file, set the deployment type to “ElementFile” and Deployment Location path to “FilesVariation Labels” in the properties window (use the Schema.xml file in the same location as your guide).
Re-deploy. Now, at long last, it should deploy without an error. You can finally create a new site based on your new web template. Without further modification, it will be displayed on the “Custom” tab of templates:
Go ahead and create a site base on your new template – that should work now as well, but don’t celebrate yet…
Roadblock 4: Error Creating Publishing Pages
On your new site, try to create a publishing page. Select Site Actions –> More Options, select Page in the left hand column, click Publishing Page for the type, and then click Create. Boom:
Since one of the main reasons to have a web template for a publishing enabled site is to be able to, you know, create publishing pages, we’re going to need to figure this out too.
Searching for the correlation id in the log files yields the following:
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index
Not very helpful, huh? While I can’t remember the exact steps I went through to troubleshoot this the first time, I can tell you that the answer lies in the way the content types are defined for the publishing pages. If you look at the elements.xml files for the master page gallery, you will find several instances where the PublishingAssociatedContentType property value is not set right. For example, Project Page reads like this:
It should be this:
At first glance, you may not even notice the difference, but you’ll note that in the correct string, you’ll find number signs as a delimiter. That’s what’s missing, and that’s what’s causing the crash when you try to create a new publishing page.
I’m not sure what the best way is to provide this information in this format, but you’ll need to find these 5 property elements in your solution (one at a time):
and replace them with the correct values:
Be sure to replace the correct corresponding Property Element (i.e. Project page for project page). Use the find and replace with a scope of entire solution – some of these appear more than once.
Still with me? Didn’t think so, but I’ll plow on anyway, because that’s the last road block. Right click-deploy, create a new site, create a publishing page, everything should be working now.
Final steps: Customization
At this point, you should have a working web template solution, but there are a few other things you may want to clean up:
- Edit the elements.xml file under the Web Templates folder to add a Display Category element. This puts your web template under a tab you name rather than the default “Custom” tab
- While editing the elements file, give your web template a more appropriate Name and Title
- Depending on your source web site, you may have path length issues. Visual Studio is pretty good about updating references when you rename folders, so you should be able to find folders that you can reduce (drastically in some cases) the length of the folder name to prevent path length issues.
- Rename your features. Check the contents of the features to see which feature is doing what and rename appropriately.
- Make your features hidden – there’s no reason for a user to interact with these features, they’re just used to help deploy content when you create sites based on your web template. Hide them to prevent confusion.
NOTE: one other issue I encountered when writing this was an error during deployment from Visual Studio:
Error occurred in deployment step ‘Activate Features’: Specified data type does not match the current data type of the property.
This doesn’t seem to affect the web template itself, it’s more a case of the site I’m using as a deployment target is in a state that no longer allows for successful activation of the features. I didn’t bother trying to resolve the issue since it didn’t keep me from successfully creating a web template I could use to create new sites, and the site I was using as a deployment target was just a throwaway anyway.