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:
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.
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
Sudheer
SharePointsol.com