Thursday, August 28, 2014

SharePoint Branding Without Governance Heartburn: Create a Page Layout Where Users Can Style a Page Themselves

Creating a consistent brand experience in SharePoint is a rewarding feeling. There's something satisfying about going to each page and having a similar look and feel. Try as you might, there's always going to be an exception where a page, or a site falls outside of the branding aesthetic. In this post I'll show you a clever branding solution that'll empower end users and prevent governance heartburn for your SharePoint support team.

Let's talk about the use case a little more in-depth: You have a heavily customized master page that all subsites use. One subsite has pages that have a different look and feel, but not customized to the point that it  warrants the need for a second, custom master page. These are fairly static pages that are updated only every now and then, and these updates may include CSS changes and or the need for custom JavaScript.

The solution here will allow a user to create and edit their own CSS and JavaScript directly in a page layout without having to fiddle around the site's CSS stylesheet(s) or deal with the Style Library.

First, some columns are needed. Create a single line of text column called "Page CSS Class", a multiple lines of text column called "Additional CSS", and a multiple lines of text column called "Additional Script." The Page CSS Class column will allow users to give the page a CSS class to target, while the other two columns are for additional CSS and JavaScript respectively.

Now create a page layout for the content type.

At the top of your page layout, add this:

<asp:content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">



<asp:Literal id="litAdditionalCSS" runat="server"></asp:Literal>



</asp:Content>

Then, in the main content area, add this:

<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">

<asp:Panel id="pnlPageWrapper" runat="server">

.

.

.

<asp:Literal id="litCustomJS" runat="server"></asp:Literal>

</asp:Panel>

</asp:Content>

Where you want the Edit Mode Panel to reside on your page layout, add the following:

<PublishingWebControls:EditModePanel ID="EditModePanel1" PageDisplayMode="Edit" runat="server" CssClass="edit-mode-panel">

<table>

<tr class="pageCSSClass">

<td class="pageCssClass">Page CSS Class</td>

<td><SharePointWebControls:TextField ID="PageCssClass" DisableInputFieldLabel="true" FieldName="PageCssClass" runat="server" /></td>

</tr>

<tr class="additionalCSS">

<td class="pageCssClass">Additional CSS</td>

<td><SharePointWebControls:TextField ID="AdditionalCSS" DisableInputFieldLabel="true" FieldName="AdditionalCSS" runat="server" /></td></tr>

<tr class="additionalScript">

<td class="pageCssClass">Additional Script</td>

<td><SharePointWebControls:TextField ID="AdditionalScript" DisableInputFieldLabel="true" FieldName="AdditionalScript" runat="server" /></td></tr>

</table>

</PublishingWebControls:EditModePanel>

But before we let the end users make the page their own, some C# is required in the code-behind of the page layout to place the CSS in “AdditionalPageHead,” and place ContentPlaceHolder, CssClass around the content area, and the JavaScript at the bottom of the page. It might be possible to do this with no-server-code and JavaScript hackery, but I have not explored this yet.

Here’s the code-behind:

if (pnlPageWrapper != null)

{

    if (SPContext.Current.ListItem[FieldDefinitions.PageCssClass.InternalName] != null)

    {

        string cssClass = SPContext.Current.ListItem[FieldDefinitions.PageCssClass.InternalName].ToString();

        pnlPageWrapper.CssClass = cssClass;

    }

}



if (listAdditionalCSS != null)

{

    if (SPContext.Current.ListItem[FieldDefinitions.AdditionalCSS.InternalName] != null)

    {

        string additionalCSS = SPContext.Current.ListItem[FieldDefinitions.AdditionalCSS.InternalName].ToString();

        litAdditionalCSS.Text = additionalCSS;

    }

}



if (listAdditionalScript != null)

{

    if (SPContext.Current.ListItem[FieldDefinitions.AdditionalScript.InternalName] != null)

    {

        string additionalCSS = SPContext.Current.ListItem[FieldDefinitions.AdditionalScript.InternalName].ToString();

        litAdditionalScript.Text = additionalScript;

    }

}

Publish the page layout and deploy that code. Now when you edit the page you'll have the new fields in the page layouts and users can get styling and scripting in no time!

clip_image001

Users can go forth and style web parts, a table in a publishing field, and whatever else is on the page. Just be sure that the code contains the appropriate tags such as <style> and <script>. SharePoint isn't that smart.

I cannot recommend exposing these fields on every page layout on every page, because what's the point of branding then? These should only be exposed when needed. Additionally, your security model on your site should ensure that not any Tom, Richard, or Harry can edit pages.

The sky is really the limit with this solution. The best part of this solution is if the page goes sour, it won't bring down the site for everyone; just a page. All the fun of master page branding with none of the ramifications!

In the interest of full disclosure, I can’t take credit for this solution. Credit goes to Steve Samnadda for coming up with this. He would have blogged about it but he's too busy putting out the world’s SharePoint fires.