Branding SharePoint 2013 My Sites with Feature Stapling

Hi,

Here is a quick guide for branding SharePoint 2013 My Sites using Feature Stapling.

Create a new Sharepoint Solution.
Select "Farm solution" then provide the correct URL to your MySite Host (in my case I'm using "/my") then click Finish.

Step 1 : Provisioning the custom masterpage
Add a new Module to the projet.

As a starting point just copy the original my sites masterpage from "\15\TEMPLATE\FEATURES\MySiteMaster\mysite15.master" into the project and rename it "CustomMySite.master" and integrate your HTML/CSS design to it. EDIT : if you are adding a new file (css, png, jpg,...) that you are referencing in the master consider using the LAYOUTS folder to keep url reference simple. Alternatively you can use a provisioning feature to store it in a library instance on the site but this method can be unsafe as the url may be inconsistent and therefore will require to unghost the masterpage to edit the html.

Edit the Elements.xml and copy this:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="ML_MasterPages" List="116" Url="_catalogs/masterpage" Path="ML_MasterPages" RootWebOnly="TRUE">
    <File Url="CustomMySite.master" Type="GhostableInLibrary" />
  </Module>
</Elements>

You'll have to add the module to the feature you will create in step 2.

Step 2 : Applying the custom masterpage to the site
We'll use an event receiver to apply the new master.

Add a new Feature with scope "Site" and name it "Site_ApplyCustomMasterPage";

Add an event receiver to the feature.

Add the following code:
namespace ClientName.MySitesBranding.Features.Site_ApplyCustomMasterPage
{
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;
    using System;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;

    [Guid("{your Guid}")]
    public class Site_ApplyCustomMasterPageEventReceiver : SPFeatureReceiver
    {
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SPSite siteCollection = (SPSite)properties.Feature.Parent;
            string masterUrl = SPUrlUtility.CombineUrl(siteCollection.ServerRelativeUrl, "_catalogs/masterpage/CustomMySite.master");

            foreach (SPWeb web in siteCollection.AllWebs)
            {
                try
                {
                    web.MasterUrl = masterUrl;
                    web.CustomMasterUrl = masterUrl;
                    web.Update();
                }
                catch
                {
                    if (web != null)
                        web.Dispose();

                    throw;
                }

                if (web != null)
                    web.Dispose();
            }
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            SPSite siteCollection = (SPSite)properties.Feature.Parent;
            string masterUrl = SPUrlUtility.CombineUrl(siteCollection.ServerRelativeUrl, "_catalogs/masterpage/mysite15.master");

            foreach (SPWeb web in siteCollection.AllWebs)
            {
                try
                {
                    web.MasterUrl = masterUrl;
                    web.CustomMasterUrl = masterUrl;
                    web.Update();
                }
                catch
                {
                    if (web != null)
                        web.Dispose();

                    throw;
                }

                if (web != null)
                    web.Dispose();
            }
        }
    }
}

Step 3 : Stapling the "apply mastepage" feature to the personal site template
This action will hook your feature to any new personal site that will be created after staple is effective. If you need to apply the branding to existing personal write a PowerShell script that activates the feature for each "/my/personal/xxx" :)
NOTE : As the MySiteHost (the "/my" root url) will usually already exist on the customer's target platform when they create their "User Profile Application Service" you'll have to manually activate the "ApplyCustomMasterPage" feature on that site collection (or think PowerShell if needed)

Create a new Feature with scope "Farm" and name it "Farm_MySiteStapler".

Then create a new empty Element name it "ML_ApplyCustomMasterPageStapler".

Add the followin code
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <FeatureSiteTemplateAssociation Id="{the Guid of the Site_ApplyCustomMasterPage feature}" TemplateName="SPSPERS#2" />
</Elements>
Note that in SharePoint 2013 the Template to staple is "SPSPERS#2" whereas in SharePoint 2010 you had to staple "SPSPERS#0".


Add the module to the Stapler feature.

Your projet should look like this:
 At this point the branding will actually work for the root sites, if you wish to apply template to any subsite that will be created (such as Blogs,...) you need to follow step 4 to hook the WebProvisioned event.


Step 4 : Applying the masterpage to any subsite created under the my site
Add a new Event receiver "ER_MySite_ElementsWebProvisioned".

Selected the web event "a site was provisioned".

Then enter the following code:

namespace ClientName.MySitesBranding.Receivers.ER_MySite_ElementsWebProvisioned
{
    using System;
    using Microsoft.SharePoint;

    public class ER_MySite_ElementsWebProvisioned : SPWebEventReceiver
    {
        public override void WebProvisioned(SPWebEventProperties properties)
        {
            SPWeb web = properties.Web;
            SPWeb rootWeb = web.Site.RootWeb;
            web.MasterUrl = rootWeb.MasterUrl;
            web.CustomMasterUrl = rootWeb.CustomMasterUrl;
            web.Update();
        }
    }
}
Now add the Event receiver to the "Site_ApplyCustomMasterPage" feature.

Your project should look like this:

Deploy your solution, activate the Farm feature and connect with a new user to his MySite check that the new master is applied. (alternative is to delete your current MySite and connect to the site to force automatic re-creation)
Your done :)

Edit: These are clues on how to solve common problems
* "The newsfeed and about me pages are styled, but looking at the urls these are all default screens and don't belong the personal mysites of individuals. Pages like blogs and apps have /personal/*username*/ in the url and these are not being properly styled as part 4 should be doing."
=> This means that the stapler feature is not working (step 3). Check the "Farm_MySiteStapler" feature, it should be in charge of activating the "Site_ApplyCustomMasterPage" feature for each new personal site created. If the personal site already exists you should run a PowerShell activation for each of them as they didn't initialised with the stapled feature.
Try Mat's code it should do the trick (Thx Mat):
Get-SPSite http://{your-server-name}/my/personal/* | ForEach { $_.URL } | ForEach { Enable-SPFeature -Identity {your-solution-name}_Site_ApplyCustomMasterPage -URL $_ }


* "My custom masterpage gets applied to the About me and the Newsfeed but not the blog, tasks and apps pages."
=>This means the event receiver "ER_MySite_ElementsWebProvisioned" is not working. Check that the ER is in your feature. You can use SharePoint Manager (http://spm.codeplex.com/) to see the EventReceivers collection of the SPSite object or through PowerShell
$site = Get-SPSite http://mydevsite/my/personal/djavanroa
$site.EventReceivers

Our custom ER should be listed.

Comments

Bun Virus said…
Great post. just wondering, is it possible to create the compose look/theme to work for both mysite and personal site just like this post you created?
Khurram Nazir said…
Very nice post. looking for last two months such info...
Djavan ROA said…
@Bun Virus, you can add an other stapple to "SPSMSITEHOST#0" but as it's a one-time activation it maybe useless as usually the User Profile Application Service will already exist and the MySiteHost site collection already created. Stappling will only work for a new instance, so it maybe just activated it manually for the host site col ;)
pam said…
Thanks for your sharing. Unfortunately, I follow all the steps, but the personal site still use original master page instead of customized one. Any help would be greatly appreciated.
pam said…
I think the problem might be my personal site is a new site collection under MySite host. Do you know how to branding site collections using the same approach?
Anonymous said…
Thanks, man.
Sin said…
I tried it, and it did not work, the feature(scoped to site collection) will not activate on new personel sites. If you activate the feature manually on the newly created personel site, it gets applied. Any idea on how to fix this?
Sind said…
It worked when I provided the correct Feature ID :) Got it from Get-Spfeature powershell command.
Raja said…
Hi

I am getting error when activating the feature in site collection when include event receiver on step 4. But feature is working when I end up with step 3 and deploy and activate feature. Any comments on this.

Thanks
Raj
Djavan ROA said…
Raj, have you checked the ULS error message?
Raja said…
Hi Djavan ROA
Custom master page is not copied to the sub sites (Newly created) and feature is not activated. When I activate the feature manually, file not found error page appears. I think this is because of no custom master page found in the master page library.
Any suggestions
Thanks
Raj
Is it really necessary to dispose the web objects you're enumerating? What i've heard you should only dispose web and site objects you instantiate yourself.

Best regards
Chris Hughes said…
Hi
This all works great! When a Blog site is created can someone please tell me how I can activate another custom feature.
New to this so apologies if a daft question
Djavan ROA said…
@Rickard Fjeldseth

from MSDN:
"Best practice is to dispose explicitly of individual Web sites that are retrieved from the collection that is returned through the AllWebs property."
see:
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spsite.allwebs.aspx
and
http://msdn.microsoft.com/en-us/library/aa973248(v=office.12).aspx
;)
Djavan ROA said…
@Chris Hughes: Create an other stappling for you feature and attach it to the "BLOG#0" id.
http://wellytonian.com/2012/07/sharepoint-2013-site-templates-powershell-codes/
Shamak said…
I am trying to brand mysite host and the personal sites. I followed the steps listed above and am getting the following error while deploying the solution:

The Project Item "ML_ApplyCustomMasterPageStapler" cannot be deployed through a Feature with Farm scope.

I am new to sharepoint so I may be missing something basic. Please let me know where could I possible have gone wrong.

Thanks,
Shamak
Anonymous said…
Hi Djavan

Great guide and works 100% for me - with no visual basic experience.

However I would like to change something I assume quite simple but having no luck.

This feature replaces both custom and default master pages. What would I need to change in order for it to just replace the "default" master and not both which includes the "Custom Master Page"?

Reason being is the my custom master page is not compatible with system pages such as dialog form, when you share or when one creates a new page etc.

Thanks in advance!
Elitzur said…
@Shamak - you are getting that error since you are trying to add a module ro farm feature. you cant. you need to read the article again and when the you need to add an empty element:
right click ->add new item->empty element
Elitzur said…
This comment has been removed by the author.
Unknown said…
Thanks for this post. I am getting an error "401 UNAUTHORIZED" when I activated the feature on the My Site Host Site Collection. Could you please help me to resolve this issue? This error comes whenever I click any link of Host Site Collection which calls layouts start page like _layouts/15/start.aspx#/default.aspx or _layouts/15/start.aspx#/_layouts/15/settings.aspx. Any help would be appreciated.
Unknown said…
Great Article, and kind of worked for me.

MySites, Newsfeed, About Me, all have the new style. Blog & Sites, on the other hand, are just a blue band across the top of the screen with my name on the right with an About Me and Sign Out option in it's menu. I've deleted my Personal\SXF site and tried again, with no luck. Any ideas?
Djavan ROA said…
@Stephen : Check that your WebProvisioned event receiver is attached to your site, you can use http://spm.codeplex.com/ for that ;)
Travis Obrycki said…
Thanks, everything worked great except when I attempted to add the Webprovisioned event listener like @Stephen. It actually broke the ability to provision new Personal MySites. I removed the Listener from the feature and it works applying the master page to the new Mysites but obviously not the subsites.
Joakim said…
Hi and thanks for a great article. I have the same problem as Stephen. My custom masterpage gets applied to the About me and the Newsfeed but not the blog, tasks and apps pages.
Tried to use Sharepoint Manager 2013 but don't know what and where to look.
Anonymous said…
I have the same issue as Travis and Joakim,

Was anyone able to get past this? Would really appreciate some insight if you have!

Thanks,
Shereen
Mat said…
Excellent article, really helpful, but I have the same issues as a lot of the people above in the comments. The newsfeed and about me pages are styled, but looking at the urls these are all default screens and don't belong the personal mysites of individuals. Pages like blogs and apps have /personal/*username*/ in the url and these are not being properly styled as part 4 should be doing.

I can work around this by using powershell on the server to go through all the personal sites and activate the feature, but I have to run this every time a new user accesses the site or they will be left with the wrong styling. (As it does no harm I may just run this on a schedule every day anyway).

For anyone who wants it (or can improve on it) the powershell is here...

Get-SPSite http://{your-server-name}/my/personal/* | ForEach { $_.URL } | ForEach { Enable-SPFeature -Identity {your-solution-name}_Site_ApplyCustomMasterPage -URL $_ }
Unknown said…
Can you elaborate more on "integrate" your CSS into the master page in step one? The stapler seems to be working fine, and we are referencing a custom css file in the master, but our styling is still not transferring to the personal sites. Any thoughts on what we might be doing wrong and how to fix it?
Jeff M. said…
I am running into an issue with Step 4:

Cannot initialize the following SharePoint project item: 'ER_MySite_ElementsWebProvisioned'. This item requires a type provider that has the following ID, but this provider could not be found: 'Microsoft.VisualStudio.SharePoint.EventHandler'. Reinstall the extension that provides this item type, or remove the item from your project.

Project: ClientName.MySitesBranding

Can someone please help??
Anonymous said…
I get the stapling feature to apply properly, the master page is set properly, but the content of the top level mysite does not change. Is there something I'm missing?
Anonymous said…
Hi ,

Thanks , Nice Post . its working for existing user but in my scnerio , I want stapling for new mysite(SharePoint 2013) user .
For example : I am new in my site personal ,then first time I am using or filling mysite activity but it didn't changes the master page as expected stapler behaviour .
If anyone have any idea so please eloborate me.
Alex said…
This comment has been removed by the author.
Shafaqat Ali said…
Hi

If there is any change in master page, do we need to redeploy everything?
Unknown said…
HI Djavan ROA Thanks for Sharing the Post.

I had an issue On MySite Feature Stapling, my code is working fine but the Site collection level Feature is Not activating default at the time of Provisioning the Site Collection. If i Activate that Site collection level Feature manually it's working Fine

Any Idea on this issue much Appreciated if you come back with solution
Thank you.
Feature doesnt work for new personal sites? manual or powershell activation works fine. what can be the problem?
Bart said…
This works wonders, great post!

I'm just curious, why does the stapler only activate the feature on new MySites and not ALL new sites?
Bart said…
I think I get it...the template used in the feature stapler is for the mysite site template, so it only activates for those sites.

With this in mind I also added a check to the feature activating that checks to see if the root web of the site is a mysite template, otherwise it won't activate the feature...we have different branding for other webs so I want to make sure they can't be activated there.
Bart said…
To put in the check I mentioned above, in the feature activated, after you get the spsite, put in an:
if (site.RootWeb.WebTemplate=="SPSPERS" && site.RootWeb.Configuration==2){
(activating code here...)
} else {
throw new SPException("This site isn't a MySite");
}
Unknown said…
Sorry, but completely unrelated question. I really like the colours in your VS theme... Mind sharing what theme/colours you are using?
Thanks,
Raj
Sanjay Adsure said…
Hi Djavan ROA,

Thank you for this post. I am facing the same issue which many people reported here. My custom branding is coming on default page of my site, NewsFeed. But not coming on Blog site. I also executed the powershell scripts which you mentioned. Itt's returing message that this Feayure is already activated at scope of users mysite. Any suggestions?
Sanjay Adsure said…
Hi,

Thank you for this post. I have one query, which some users have already asked. In my scenario, the custom master page branding is not getting applied to Blog site. I have executed the Powershell command also. It says that the Feature is already activated. Any suggestion?

Thanks,
Sanjay
Unknown said…
Awesome post, followed the steps and it worked without any issues. Thank you very much for the post.

If anyone having "This site has not been shared with you" issue, you can try checkin the major version of the master page. This solved issue in my case.
Karthika Shree said…
Very nice post here and thanks for it .I always like and such a super contents of these post.Excellent and very cool idea and great content of different kinds of the valuable information's.
Sharepoint Training in Chennai