Transform the “SharePoint” Suite Bar Text into a Breadcrumb with PowerShell

March 11, 2013

Where is the breadcrumb in SharePoint 2013? There isn’t one out-of-the-box, but this post helps you to get one back.

The out-of-the-box Seattle or Oslo master pages don’t have a breadcrumb located in their HTML markup. That makes navigating from sub-sites to their parent site difficult, if you have not set a good global navigation structure.

This got me thinking about a solution to create a breadcrumb that could easily be added to the SharePoint sites.

The Idea

A few weeks ago I was playing with the SuiteBarBrandingElementHtml property to change the SharePoint text in the top left corner to my company name.

Note: there are already a few blog posts about this topic, so I will not explain this. Here is the blog post of Tobias Zimmergren on how you could change the text: Change the “SharePoint” text in the top left corner.

Changing the SharePoint text to your company name could be nice if you want some extra visibility, but still I find it a bit of unused space.

So this was the starting point of my idea, what if this could be replaced with a usable breadcrumb? That would certainly make navigating through sites a bit easier.

The Solution

The SuiteBarBrandingElementHtml element only allows html code to be added, because it will just show it as plain text on your page. My approach is to make use of some SharePoint ECMAScript to retrieve the parent sites of the current site you are on, and create a breadcrumb with this information.

Code

First of all we need some JavaScript code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
(function () {
  if(document.addEventListener ) {
      document.addEventListener('DOMContentLoaded', function() {
          EnsureScriptFunc('sp.js', 'SP.ClientContext', JavascriptBreadcrumb);
      }, false);
  } else {
      window.setTimeout(function() {
          EnsureScriptFunc('sp.js', 'SP.ClientContext', JavascriptBreadcrumb);
      }, 0);
  }

  function JavascriptBreadcrumb() {
      this.elm = document.getElementById('javascript-breadcrumb');

      // Show the list link
      var list = "";
      if (ctx !== null && typeof ctx !== "undefined" && _spPageContextInfo.pageListId !== null && typeof _spPageContextInfo.pageListId !== "undefined") {
        if (ctx.listName !== null && typeof ctx.listName !== "undefined") {
            if (_spPageContextInfo.pageListId.toUpperCase() == ctx.listName.toUpperCase()) {
                list = "<a href='" + ctx.listUrlDir + "' title='" + ctx.ListTitle + "' style='color:#fff'>" + ctx.ListTitle + "</a> > ";

                // Check if you are inside a folder
                if (typeof ctx.rootFolder !== "undefined" && ctx.rootFolder !== "") {
                    var listUrl = decodeURIComponent(ctx.listUrlDir);
                    var rootFolder = decodeURIComponent(ctx.rootFolder);
                    rootFolder = rootFolder.replace(listUrl, "");

                    var folders = rootFolder.split("/");
                    for (var i = 0; i < folders.length; i++) {
                        if (folders[i] !== "" && typeof folders[i] !== "undefined") {
                            listUrl = listUrl + "/" + folders[i];
                            list += "<a href='" + listUrl + "' title='" + folders[i] + "' style='color:#fff'>" + folders[i] + "</a> > ";
                        }
                    }
                }
            }
        }
      }

      this.breadcrumb = "<a href='" + _spPageContextInfo.webAbsoluteUrl + "' style='color:#fff;'>" + _spPageContextInfo.webTitle + "</a> > " + list + "<span style='font-style:italic;'>" + document.title + "</span>";
      this.elm.innerHTML = this.breadcrumb;

      var clientContext = new SP.ClientContext.get_current();
      this.web = clientContext.get_web();
      this.parentweb = this.web.get_parentWeb();

      clientContext.load(this.parentweb);
      clientContext.executeQueryAsync(Function.createDelegate(this, onQuerySuccess), Function.createDelegate(this, onCreationFail));
  }

  function onQuerySuccess() {
      try {
          if (typeof this.parentweb.get_title() !== "undefined" && this.parentweb.get_title().toLowerCase() !== "intranet") {
              this.breadcrumb = "<a href='" + this.parentweb.get_serverRelativeUrl() + "' style='color:#fff'>" + this.parentweb.get_title() + "</a>" + " > " + this.breadcrumb;
              this.elm.innerHTML = this.breadcrumb;

              var clientContext = new SP.ClientContext(this.parentweb.get_serverRelativeUrl());
              this.web = clientContext.get_web();
              this.parentweb = this.web.get_parentWeb();

              clientContext.load(this.parentweb);
              clientContext.executeQueryAsync(Function.createDelegate(this, onQuerySuccess), Function.createDelegate(this, onCreationFail));
          }
      }
      catch (e) {}
  }

  function onCreationFail() {}
})();

As you can see it is not that difficult. The event listener is very important if MDS (Minimal Download Strategy) is enabled on your site, so this may not be removed (when it is removed, your breadcrumb will not render).

PowerShell Script

Applying this breadcrumb to your sites will be done via the web application SuiteBarBrandingElementHtml property. To do this you could use the following script:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
$spInstalled = Get-PSSnapin ' Select-String Sharepoint
if (!$spInstalled)
{
    Add-PSSnapin Microsoft.Sharepoint.PowerShell
}

$app = Get-SPWebApplication -Identity http://your-web-application-url

$markup = @"
<div id='javascript-breadcrumb' class='ms-core-brandingText' style='line-height: 15px; width: auto;'></div>
<script>
(function () {
  if(document.addEventListener ) {
      document.addEventListener('DOMContentLoaded', function() {
          EnsureScriptFunc('sp.js', 'SP.ClientContext', JavascriptBreadcrumb);
      }, false);
  } else {
      window.setTimeout(function() {
          EnsureScriptFunc('sp.js', 'SP.ClientContext', JavascriptBreadcrumb);
      }, 0);
  }

  function JavascriptBreadcrumb() {
      this.elm = document.getElementById('javascript-breadcrumb');

      // Show the list link
      var list = "";
      if (ctx !== null && typeof ctx !== "undefined" && _spPageContextInfo.pageListId !== null && typeof _spPageContextInfo.pageListId !== "undefined") {
        if (ctx.listName !== null && typeof ctx.listName !== "undefined") {
            if (_spPageContextInfo.pageListId.toUpperCase() == ctx.listName.toUpperCase()) {
                list = "<a href='" + ctx.listUrlDir + "' title='" + ctx.ListTitle + "' style='color:#fff'>" + ctx.ListTitle + "</a> > ";

                // Check if you are inside a folder
                if (typeof ctx.rootFolder !== "undefined" && ctx.rootFolder !== "") {
                    var listUrl = decodeURIComponent(ctx.listUrlDir);
                    var rootFolder = decodeURIComponent(ctx.rootFolder);
                    rootFolder = rootFolder.replace(listUrl, "");

                    var folders = rootFolder.split("/");
                    for (var i = 0; i < folders.length; i++) {
                        if (folders[i] !== "" && typeof folders[i] !== "undefined") {
                            listUrl = listUrl + "/" + folders[i];
                            list += "<a href='" + listUrl + "' title='" + folders[i] + "' style='color:#fff'>" + folders[i] + "</a> > ";
                        }
                    }
                }
            }
        }
      }

      this.breadcrumb = "<a href='" + _spPageContextInfo.webAbsoluteUrl + "' style='color:#fff;'>" + _spPageContextInfo.webTitle + "</a> > " + list + "<span style='font-style:italic;'>" + document.title + "</span>";
      this.elm.innerHTML = this.breadcrumb;

      var clientContext = new SP.ClientContext.get_current();
      this.web = clientContext.get_web();
      this.parentweb = this.web.get_parentWeb();

      clientContext.load(this.parentweb);
      clientContext.executeQueryAsync(Function.createDelegate(this, onQuerySuccess), Function.createDelegate(this, onCreationFail));
  }

  function onQuerySuccess() {
      try {
          if (typeof this.parentweb.get_title() !== "undefined" && this.parentweb.get_title().toLowerCase() !== "intranet") {
              this.breadcrumb = "<a href='" + this.parentweb.get_serverRelativeUrl() + "' style='color:#fff'>" + this.parentweb.get_title() + "</a>" + " > " + this.breadcrumb;
              this.elm.innerHTML = this.breadcrumb;

              var clientContext = new SP.ClientContext(this.parentweb.get_serverRelativeUrl());
              this.web = clientContext.get_web();
              this.parentweb = this.web.get_parentWeb();

              clientContext.load(this.parentweb);
              clientContext.executeQueryAsync(Function.createDelegate(this, onQuerySuccess), Function.createDelegate(this, onCreationFail));
          }
      }
      catch (e) {}
  }

  function onCreationFail() {}
})();
</script>
"@

$app.SuiteBarBrandingElementHtml = $markup
$app.Update();

Result

Show LIbrary and Folders
Show LIbrary and Folders
Breadcrumb Sub-Sub-Site
Breadcrumb Sub-Sub-Site
Breadcrumb Sub-Site
Breadcrumb Sub-Site
Breadcrumb Top Site
Breadcrumb Top Site

Download

Download the script here: Suite-Bar-Breadcrumb.ps1 - update

Revert to the default

If you want to revert to the default SharePoint text, it only requires to run the following script.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$spInstalled = Get-PSSnapin ' Select-String Sharepoint
if (!$spInstalled)
{
    Add-PSSnapin Microsoft.Sharepoint.PowerShell
}

$app = Get-SPWebApplication -Identity http://your-web-application-url
$markup = "<div class='ms-core-brandingText'>SharePoint</div>"
$app.SuiteBarBrandingElementHtml = $markup
$app.Update();

Updates

13/06/2013

This solution won’t work on SharePoint Foundation farms, on these farms the SocialRibbonControl feature is not present. A workaround could be to create your own solution (with an element file) to apply the control to the pages.

The element file looks like this:

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Control Id="SuiteBarBrandingDelegate" Sequence="100"
        ControlClass="Microsoft.SharePoint.WebControls.SuiteBarBrandingElement"
        ControlAssembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
</Elements>

22/08/2013

Updated the script to make it work in IE8 and to fix a bug with checking folders.

Thank you Vicent and Max.

02/10/2013

Added the revert to default situation script.

21/11/2013

Updated the script based on the feedback from Maarten.

Comments

comments powered by Disqus