Auto Publish and Approve Your Solution Files

Applies To: SharePoint 2010

By default, every file you deploy using a sandboxed solution is left checked out. This can lead to problems depending on the type of site you are deploying to and/or the permissions of your end users.

This post focuses on Branding solutions, but anytime you are deploying a sandboxed solution these techniques should help you. This is especially important for Master Pages since these often need an approved/published version in order to be visible to anyone but the site administrators.

I found an interesting approach by Waldek Mastykarz where he suggests using a “Stamp” (Feature ID property) on each file and using that to find and check in each file. This was very cool, but requires you to modify the Elements.xml entry for each file to ensure that property is added and he also never addressed Master Pages which can be a bit of a special case.

For my needs, I generally take a simpler approach of just deploying my resources to one root folder and creating sub folders as needed. This makes it easier to find stuff, but it also means I don’t need to track each file individually. Obviously if you are doing something a little more extensive then you may need to take a hybrid approach of using the featureid property and/or just tracking the various folders you are deploying too. But for a simple branding solution you really just need to:

  1. Apply your branding to each site
  2. Publish and Approve each resource file
  3. Publish and Approve each Master Page

All of this can be done in the FeatureActivating event with a simpler helper method:

    Public Overrides Sub FeatureActivated(ByVal properties As SPFeatureReceiverProperties)
        Dim siteCollection As SPSite = CType(properties.Feature.Parent, SPSite)
        If siteCollection IsNot Nothing Then
            Dim topSite As SPWeb = siteCollection.RootWeb

            'Calculate relative path to site from Web Application root
            Dim WebAppRelativePath As String = topSite.ServerRelativeUrl
            If Not WebAppRelativePath.EndsWith("/") Then WebAppRelativePath &= "/"

            'Enumerate through each site and apply branding
            For Each site As SPWeb In siteCollection.AllWebs
                If Not site.MasterUrl.EndsWith("minimal.master") Then
                    site.MasterUrl = WebAppRelativePath & "_catalogs/masterpage/BSmain.master"
                    site.MasterUrl = WebAppRelativePath & "_catalogs/masterpage/BSminimal.master"
                End If
                If Not site.CustomMasterUrl.EndsWith("minimal.master") Then
                    site.CustomMasterUrl = WebAppRelativePath & "_catalogs/masterpage/BSmain.master"
                    site.CustomMasterUrl = WebAppRelativePath & "_catalogs/masterpage/BSminimal.master"
                End If
                site.AlternateCssUrl = WebAppRelativePath & "Style%20Library/BSResources/BS.css"
                site.SiteLogoUrl = WebAppRelativePath & "Style%20Library/BSResources/Images/BSlogo.png"
                site.UIVersion = 4

            'Publish and Approve each file
            Dim styleLibrary As SPList = topSite.Lists.TryGetList("Style Library")
            If styleLibrary IsNot Nothing Then
                Dim folders As SPListItemCollection = styleLibrary.Folders
                Dim item As SPListItem = DirectCast((From i In folders Where DirectCast(i, SPListItem).Url = "Style Library/BSResources" Select i).FirstOrDefault(), SPListItem)
                ApproveAndPublish(item.Folder, styleLibrary.EnableModeration)
            End If

            'Publish and Approve the Master Pages
            Dim mpGallery As SPList = siteCollection.GetCatalog(SPListTemplateType.MasterPageCatalog)
            If mpGallery IsNot Nothing Then
                Dim mpages As SPListItemCollection = mpGallery.GetItems(New SPQuery With {.Query = "<Where><Or><Eq><FieldRef Name='FileLeafRef' /><Value Type='Text'>RegalIC.master</Value></Eq><Eq><FieldRef Name='FileLeafRef' /><Value Type='Text'>RegalICminimal.master</Value></Eq></Or></Where>"})
                If mpages IsNot Nothing Then
                    For Each i As SPListItem In mpages
                        If Not i.File.CheckOutType = SPFile.SPCheckOutType.None Then
                            i.File.CheckIn("Feature Activation", SPCheckinType.MajorCheckIn)
                            If mpGallery.EnableModeration Then
                                i.File.Approve("Feature Activation")
                            End If
                        End If
                End If
            End If

        End If
    End Sub

    Private Sub ApproveAndPublish(folder As SPFolder, Approve As Boolean)
        If folder Is Nothing Then Return
        For Each subfolder As SPFolder In folder.SubFolders
            ApproveAndPublish(subfolder, Approve)
        For Each file As SPFile In folder.Files
            If Not file.CheckOutType = SPFile.SPCheckOutType.None Then
                file.CheckIn("Feature Activation", SPCheckinType.MajorCheckIn)
                If Approve Then
                    file.Approve("Feature Activation")
                End If
            End If
    End Sub

1. Apply your branding to each site

After gathering basic information about where the feature is being deployed and getting the correct reference URLs, we begin looping through every site in the sitecollection and setting the master page, sitelogo, and CSS settings to use our custom branding beginning in line 11.

The only thing different than the approach described in the Microsoft article, Deploying Branding Solutions for SharePoint 2010 Sites Using Sandboxed Solutions is that I am checking if the current master page is the minimal.master and if so, using my BSminimal.master file instead. This allows me to have both master pages deployed correctly, but it also allows me to restore these settings more accurately in the deactivating event (See my previous post).

2. Publish and Approve each resource file

To keep things simple, I keep all of my resource files in a single root folder within the Style Library. This makes looping through each subfolder and resource very simple to ensure that each one gets checked in and/or approved as necessary.

Lines 29-34 get a reference to the resource folder within the Style Library and pass that information over to a helper method called ApproveAndPublish. This method takes an SPFolder reference and a boolean indicating if approval is necessary or not. For the initial call, the folder is our resource folder and the approval setting comes directly from the Style Library and is found in the EnableModeration property of the SPList object.

The ApproveAndPublish method (Lines 55-68) is a recursive function that loops through every subfolder and checks in every file found. If Approval is required, it also marks them as approved.

This means you don’t have to track each file (either through stamping or keeping a list). This really cuts down on all the plumbing that is often necessary when working on a SharePoint solution.

3. Publish and Approve each Master Page

Unfortunately, Master Pages aren’t usually deployed to a sub folder and so the above technique for approval and check in has to be tweaked slightly. Lines 37-50 take care of this. Basically, we get a reference to the Master Page Catalog and use some basic CAML to isolate our master pages and then loop through them to check them in and/or activate them if required.

That’s all that’s required. You now have your files successfully deployed and ready to be used. Be sure to check out my previous post Branding Solution Cleanup. In that post I describe how to remove all of your solution files when your solution gets deactivated.

One thought on “Auto Publish and Approve Your Solution Files

  1. […] it comes to something like branding or other resource files. I’ve previously shown you how to automatically publish a major version and to approve documents as your solution deploys. In a perfect world you’ll never touch these files except through your […]

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s