SharePoint 2013 Branding with App using Master Page and Theme

With SharePoint 2013, Microsoft has been pushing for the App Model instead of Farm solution.  Below is sample code from a provider-hosted app that upload custom master page and theme (.spcolor) files to the SharePoint site, and apply theme through the App installed event.  The app is tested as high trust provider hosted app in a On-premise SharePoint 2013 environment.

It's in C# with CSOM.  Basically, the code does the following:

  • Upload custom master page
  • Set custom master page
  • Upload theme file (.spcolor)
  • Apply Theme


This is the App Event receiver class:

public class AppEventReceiver : IRemoteEventService
    {
        public SPRemoteEventResult ProcessEvent(SPRemoteEventProperties properties)
        {
            SPRemoteEventResult result = new SPRemoteEventResult();

            switch (properties.EventType)
            {
                case SPRemoteEventType.AppInstalled:
                    AppInstall(properties);
                    break;
            }
         
            return result;
        }

        public void ProcessOneWayEvent(SPRemoteEventProperties properties)
        {
            // This method is not used by app events
        }

        private void AppInstall(SPRemoteEventProperties properties)
        {
            using (ClientContext clientContext = TokenHelper.CreateAppEventClientContext(properties, false))
            {
                if (clientContext != null)
                {
                    Common.ApplyBranding(clientContext, HostingEnvironment.ApplicationPhysicalPath);
                }
            }
        }


    }


private void ApplyBranding(ClientContext clientContext, string webPhysicalPath)
        {          
         
            string masterPagePath = String.Format("{0}\\Pages\\custom.master", webPhysicalPath);

            Site site = clientContext.Site;

            clientContext.Load(site, s => s.ServerRelativeUrl, s => s.Url);
            clientContext.ExecuteQuery();

            Web rootWeb = clientContext.Site.RootWeb;          
            Web currentWeb = clientContext.Web;
            clientContext.Load(rootWeb, rw => rw.Id);
            clientContext.ExecuteQuery();
            clientContext.Load(currentWeb, cw => cw.Id);
            clientContext.ExecuteQuery();
            bool isRootWeb = false;

            #region upload and set master page
            string masterUrl = String.Format("{0}/_catalogs/masterpage/custom.master", site.ServerRelativeUrl);

            if (rootWeb.Id.ToString() == currentWeb.Id.ToString())
            {
                isRootWeb = true;
                List masterPageGallery = rootWeb.Lists.GetByTitle("Master Page Gallery");
                Folder rootFolder = masterPageGallery.RootFolder;

                FileCreationInformation fci = new FileCreationInformation();
                fci.Content = System.IO.File.ReadAllBytes(masterPagePath);
                fci.Url = "custom.master";
                fci.Overwrite = true;

                Microsoft.SharePoint.Client.File fileToUpload = rootFolder.Files.Add(fci);

                clientContext.Load(fileToUpload);
            }

            currentWeb.CustomMasterUrl = masterUrl;
            currentWeb.MasterUrl = masterUrl;
            currentWeb.Update();
            #endregion

            #region Upload and Apply theme

            string colorFilePath = String.Format("{0}\\Theme\\claret.spcolor", webPhysicalPath);
            string colourFileUrl = String.Format("{0}/_catalogs/theme/15/claret.spcolor", site.ServerRelativeUrl);

            if (isRootWeb)
            {
                List themeList = rootWeb.Lists.GetByTitle("Theme Gallery");

                Folder subFolder = rootWeb.GetFolderByServerRelativeUrl(String.Format("{0}/_catalogs/theme/15", site.ServerRelativeUrl));

                FileCreationInformation colorFile = new FileCreationInformation();
                colorFile.Content = System.IO.File.ReadAllBytes(colorFilePath);
                colorFile.Url = "claret.spcolor";
                colorFile.Overwrite = true;

                Microsoft.SharePoint.Client.File colorFileToUpload = subFolder.Files.Add(colorFile);

                clientContext.Load(colorFileToUpload);
            }

            currentWeb.ApplyTheme(colourFileUrl, null, null, true);
            #endregion

            clientContext.ExecuteQuery();
        }

This approach will work well if your master page is just re-arranging the components on the master page or using only SharePoint OOTB components (maybe created through Design Manager).  If you need any custom components (i.e. footer, navigation, ...etc), you'll have to convert those components to be running client side code instead.

Comments

Popular posts from this blog

SharePoint 2013 App Details Page Error

SharePoint 2013 - Working with Display Template for Content Search Web Part

SharePoint 2013 Features Information List