A Content Editor Web Part for every home!

In this post, I am going to describe a technique that allows end users to control multiple SharePoint pages from a central location. As the title suggests, the cornerstone is the Content Editor Web Part.

I’ll first describe the implementation, then I’ll show it at work on two examples: a cross-site menu and a “Breaking News” scenario. We’ll complete our tour with a live demo.

The scenario

When deploying SharePoint in your organization, you’ll rely on site templates, either the OOTB ones or – most likely – your own set. At some point you’ll certainly be confronted with the following issue: how to roll out updates across multiple existing sites?

SharePoint 2007 offers various options (and btw brings significant improvements compared to SharePoint 2003). You can modify Master Pages or the CSS. You can also rely on features, a powerful option, especially interesting for customizations applied on a site by site basis.

In many cases however, you’ll find out that these options don’t work for you, for various reasons. First of all, you may not have access to these tools, for example if you are in a hosted environment, or part of a big, standardized organization. Also these are heavyweights, and they are an overkill for simple changes.

So here is an additional, lightweight method accessible to end users. It doesn’t replace all of the above, but it comes in handy and is very responsive for light adjustments.

My proposal: a Content Editor Web Part for every home

The idea is to include a remote control on your SharePoint pages. See the picture below:



In each site template, I have included a hidden CEWP at the bottom of the home page. This CEWP is linked to a file stored in a central location – CentralScript.txt – through the “Content Link” option in the CEWP menu. All users have read permissions on CentralScript.txt.

Each site based on my templates will have this CEWP. So through the scripts added to CentralScript.txt, I can remotely control the content of the home pages.

Note that site owners may not be aware of the purpose of your remote control Web Part, and could be tempted to remove it from the home page. To avoid this, you’d better find a catchy name that clearly states the purpose of the Web Part and/or states that it should not be deleted.

The above picture shows a simplified implementation with a single site collection. It can be extended to work with multiple site collections or even multiple servers.

When working on a SharePoint architecture, I usually create a central “Utilities” site. This site will host various content that is shared across teams: logos, icons, scripts, etc. All the users are given read access to this site that contains no confidential information. This is where the CentralScript.txt file resides.

This technique can also be applied to an existing environment. But in this case each site owner will have to add the CEWP manually.

Note that CentralScript.txt doesn’t have to contain scripts, you can start with an empty file. The idea is to anticipate, and to give your architecture the flexibility to accomodate future needs.

Example 1: cross-site menu

How can you share a list of links across sites? If you create a SharePoint list of links, it is not easy to share it across sites within a site collection, and it is even more challenging to share it across site collections or across servers.

Let’s see how I can achieve his using my remote control. I’ll add to CentralScript.txt a script that:
– creates a list of links
– displays it as a drop-down menu, adopting the look and feel of each SharePoint site
– positions it as a tab on the top right of each page

Here is the expected result:


If you already see a “Site Actions” menu in the top right, the cross-site menu will be added next to it:


You’ll notice that the menu adopts the theme of each site (resp. Breeze and Lacquer in the two above screenshots).

To write the script, I adapted a post I wrote last year :

<script type="text/javascript">

var CustomMenuItemText = new Array();
var CustomMenuItemLink = new Array();
var CustomMenuItemIcon = new Array();
var CustomMenuItemNote = new Array();
var CustomMenuString = "";

// CustomMenuName: the display name for your menu
// CustomMenuID: specific id for your menu (no blank or special character)
// LargeIcons: "true" or "false". "true" will display large icons and the description.
// CustomMenuItemText, CustomMenuItemLink, CustomMenuItemIcon, CustomMenuItemNote: enter for each link the title, URL, icon URL and description
// Questions: Christophe@PathToSharePoint.com

var CustomMenuName = "Cross-site menu ";
var CustomMenuID = "CrossSiteMenu";
var LargeIcons = "true";

CustomMenuItemText[0]="Send e-mail to Christophe";
CustomMenuItemLink[0]="mailto:Christophe@PathToSharePoint.com?subject=Drop-down menu";
CustomMenuItemNote[0]="Feedback and questions are welcome!";

CustomMenuItemText[1]="Path to SharePoint - Blog";
CustomMenuItemNote[1]="Tips and best practices for SharePoint end users";

CustomMenuItemText[2]="Other SharePoint Blogs";
CustomMenuItemNote[2]="More than 350 blogs - all about SharePoint!";

// Build the custom menu

var CustomMenuIDMain = CustomMenuID + "Main";
var CustomMenuIDt = CustomMenuID + "_t";

CustomMenuString += '<span style = "display\:none\;"><menu id = "' + CustomMenuIDMain + '" largeIconMode = "' + LargeIcons + '"><\/menu><\/span>' ;
CustomMenuString += '<div><div><span><div ID=\'' + CustomMenuIDt + '\' class="" onmouseover="MMU_PopMenuIfShowing(this);MMU_EcbTableMouseOverOut(this, true)" hoverActive="ms-siteactionsmenuhover" hoverInactive="" onclick=" MMU_Open(byid(\'' + CustomMenuIDMain + '\'),MMU_GetMenuFromClientId(\'' + CustomMenuID + '\'),event,false, null, 0);" foa="MMU_GetMenuFromClientId(\'' + CustomMenuID + '\')" oncontextmenu="this.click(); return false;" nowrap="nowrap"><a ID=\'' + CustomMenuID + '\' href="#" style="cursor\:hand\;white-space\:nowrap\;" onfocus="MMU_EcbLinkOnFocusBlur(byid(\'' + CustomMenuIDMain + '\'), this, true);" onkeydown="MMU_EcbLinkOnKeyDown(byid(\'' + CustomMenuIDMain + '\'), MMU_GetMenuFromClientId(\'' + CustomMenuID + '\'), event);" onclick="javascript:return false;" oncontextmenu="this.click(); return false;" serverclientid="' + CustomMenuID + '">';
CustomMenuString += CustomMenuName + '<\/a><img alt="" src="\/_layouts\/images\/whitearrow.gif" align="absBottom" border="0"\/><\/div><\/span><\/div><\/div>' ;

var m = document.createElement('td');
m.className = "ms-siteactionsmenu";
m.id = "CustomMenutd";
m.innerHTML = CustomMenuString;

var toprightactionsmenu = document.getElementById('siteactiontd');
toprightactionsmenu.parentNode.insertBefore (m,toprightactionsmenu);

// Build the menu content
var i=0;
CustomMenuString = "" ;
for (i=0; i<CustomMenuItemLink.length; i++) {
CustomMenuString += '<ie\:menuitem type="option" IconSrc="' + CustomMenuItemIcon&#91;i&#93; + '" onMenuClick="window.location = \'' + CustomMenuItemLink&#91;i&#93; + '\'" text="' + CustomMenuItemText&#91;i&#93; + '" description="' + CustomMenuItemNote&#91;i&#93; + '"><\/ie\:menuitem>' ;

document.getElementById(CustomMenuIDMain).innerHTML = CustomMenuString ;


Example 2: Breaking News

How can you quickly forward breaking news to your users community? A natural way would be to display a message on top of each home page:


Well, that’s something our central script can handle. Add the following code to CentralScript.txt:

<script type="text/javascript">
var breakingnews = '<span style="width:150px;">&nbsp;</span><span class="ms-sitetitle" style="color:red;"> Note to all users: these are "Breaking News"!</span>';
var topleftplaceholder = document.getElementById("ctl00_PlaceHolderGlobalNavigation_PlaceHolderGlobalNavigationSiteMap_GlobalNavigationSiteMap");
var breakingnewstag = document.createElement("span");
breakingnewstag.innerHTML = breakingnews;

Other examples

Many of the scripts published on this blog or other blogs can be injected in the page through this central control. Of course you can also include styles.

For example, you could decide to adjust the columns width on the home page, or add a toggle button to the QuickLaunch menu. You could also use this for random quotes, a shared calendar, etc.

If your design relies on jQuery plugins, you could use CentralScript.txt to reference them. Version upgrades will be far easier in this central location than if you call the plugins from each site!

Live demo

I have applied this example to my demo sites. CentralScript.txt is stored in a central location, along with other utilities. This demo file includes 3 scripts: the cross-site menu, “Breaking News”, and the expand/collapse buttons. It interacts with:
– the top level home page
– the sub-sites (click on the tabs)
– a site located on a different server

Comparison with other methods

If you rely on client side scripts for your design, a centralized control will greatly facilitate the maintenance of your sites. I already mentioned the example of jQuery plugins, which need to be regularly updated.

Compared to other design methods like Master pages or CSS, the approach described here is more flexible and responsive, especially in hosted environments or if your team is part of a large organization. The changes are applied through a CEWP, which means that they are non-destructive, and can easily be rolled back (activate version history on the library where you store the CentralScript.txt). Another key advantage, it can work across multiple site collections or multiple servers.
However, this method won’t be robust enough for heavy lifting.

Also, keep in mind these two constraints:
– Customizations only apply to the pages that have the CEWP. In comparison, a Master page or CSS change would apply to all pages.
– The link to the central script is hardcoded in the template. It means that the location of the script cannot be changed easily.

84 thoughts on “A Content Editor Web Part for every home!

  1. Christophe,

    Great article. I have been wanting to discuss what I do with regards to this. I have access to Designer and Masters.Pages and thus can add this to the master page, but for those that do not have such access, this is a great way to address the issue.

    I centralize all scripts and then use the CEWP link area to link to the centralized file. This gains the same result that anywhere that file is used a new version applied will affect all pages automatically.

    Great best practice.

  2. Christophe,

    I love this. I do have a question on one thing. When an Owner/member goes to the parent site they will see the Site Actions menu that is standard. Does the Cross SIte Menu overwrite this?


  3. Thanks for the comments Peter.

    Even with access to Master Pages, you may sometimes prefer this method. For example if your customizations are specific to the home page and don’t apply to the whole site.

  4. Christophe,

    Thanks for the reply. Unfortunately I am not able to surface the top cross site menu after adding script into contentscript.txt. The permissions are set to read as the article advises. I am using a theme for the site but beyond that nothing really customized that might lead meto believe this is the issue.

    Any ideas. Are other plugins required?

  5. Pingback: Links for February 17, 2009 « Steve Mullen’s Blog

  6. Pingback: Charts, graphs and visual indicators in WSS | End User SharePoint

  7. Chris,
    Sorry, i’m nw in sharepoint. In the hidden CEWP how it’s link to the others webpart e.g. calender..etc. I’ve gone thorugh the tiny calender but still fail. Need your help.

  8. The CEWP is actually not directly linked to the other Web Parts. It just applies scripts or styles to the resulting html page.
    The tiny calendar is an easy one, just make sure you followed all the steps. For more details, read my post on the CEWP.

  9. How Cristophe, first of all thanks for your grat work!
    Just a question: the cross site menu works also cross site collections?
    Because I’m getting the following error:
    “Cannot retrieve the URL specified in the Content Link property. For more assistance, contact your site administrator.”
    Thanks a lot,

  10. Barbara: yes, this works across site collections, and even across SharePoint farms. Check if the link you typed is correct, and make sure you have read access to the source file.

  11. I checked both and:
    – the link is typed correctly, but cross site collection when checking the link and the destination file opens in a new window, I got that there is a javascript error (on line 51 of your script)
    – the users has god reading access on the source file

    Thank anyway

  12. Barbara: are you using the above code as is?
    Also, does the script work fine if you paste it directly in the source editor of the CEWP, instead of linking to it?

  13. Hi Christophe

    I am using your cross site tool which is pretty nice, but the application I am opening opens up over my website, so wanted to use Lytebox to open the in a separate window.

    Any ideas as to where the code needs to go?

    I have tried a few places – the only one that worked was sticking it in the but the info appeared in the webpart on the page – it did open the lytebox though. Anywhere else I stuck it made it disappear from the site.


  14. Hi Christophe

    Thanks for the email. I have tried adding in the info, but have not had much luck.

    The code I am trying to add is

    New NCR

    Any ideas as to where this needs to go would be appreciated.



  15. Just recently found your site and having quite a bit of fun learning. An issue I am having is that the earlier code for the ‘simple drop-down menu’ works great, but the code above for adding a menu at the top doesn’t work for me. THe CentralScript works for me, but the menu code doesn’t work through the CentralScript nor through a plain ole CEWP. Can a server admin restrict the ability for a site admin to add this menu? I can add the ‘breaking news’, but no luck on the drop-down. 😦 I tried to compare the old code with your new code above but there is too much different for me to understand what could be the culprit. I did a straight copy/paste from your code above. Ideas?

  16. This is a great idea, but I noticed in your example that the UTILS site is part of the site collection. I’ve been trying to implement the UTILS concept, but from a stand-alone site collection…with the idea that all the CEWPs, across site collections, will reference that particular sitepath and thus there’s only one instance of a particular script to maintain across the webapp.

    I haven’t had much success with this though, although I’ve tried a lot of different permutations, including renaming the script with a .js filextension, wrapping it in html (), and also trying to call it from within the source editor. The CEWP content link seems to only want to reference items within the current site collection. I know the permissions to the utils site are wide open, and I know I must be doing something wrong in invoking the script, but what….

    In short, could you possibly show how to invoke
    from a CEWP sitting on


  17. Renee, see my live demo: one site is not in the same site collection, not even on the same server. I’d suggest to double check your permission settings. Also, the JavaScript you’re using may have some cross-domain restrictions (which have nothing to do with the fact that you use a CEWP).

  18. Hi Christophe,

    This sounds like a cool idea – I have a problem and wanted to know if you think this could be a solution. I’m trying to create a central calendar made of all the events in the calendars of subsites bellow. could I do it with this CQWP? do you have any other suggestions (besides a bat file that runs on a daily basis and copies the events…)
    thanking you in advance!


  19. Is it posible to tweak the cross-menu script a bit so that when a user clicks on a menu item it opens in a new browser window? I’d like to use it as a launchpad to other sites, but leave Sharepoint open in the current window. I’m not a javascript junkie, so I’m not sure how to put this into the script.
    Any ideas or advice are appreciated.

    • Brad, the script reuses an existing JavaScript function provided by SharePoint, which doesn’t offer the option to open links in a new window. You would need to write your own script for that.

  20. I have this up on my site collection home page and it’s working great.

    1) On my sites, the Cross Site Menu and the Site Actions menus are sort of half on top of each other. It’s possible to see and use each one correctly, but for users who will have both appear (admins and a few others like myself) it looks weird and sort of like a mistake. Can I put some space between them?

    2) I (wrongly) assumed that once this was added, it would appear on every page in the site, regardless, just like the Site Actions menu does. Is it possible to achieve that easily?

    Thanks again for all you do!

  21. Hi Christophe,

    Love your work! The “Breaking News” web part will REALLY help us surface emergency alerts on the hospital intranet site I maintain.

    I have slightly modified the masterpage we use for our sites, and I’m sure that’s why I can’t get the web part to appear:

    1) Tried linking to CentralScript.txt as well as pasting the scripts directly into the Source Editor. Cross-Site Menu works perfectly either way. Breaking News doesn’t work either way.

    2) Tested on a site which doesn’t use my modified masterpage, and the Breaking News script also works as intended.

    I can email you a screen cap of the modified page and/or the relevant part of the masterpage code so you can see what I’ve done. Unless you already know what I must have removed from my masterpage that is now breaking your script?


    • My sample script is looking for an HTML element on the page with the following id:

      If your changes have removed this element, then the script won’t work. In this case, you just need to choose another anchor on the page, or directly add an element in the CEWP itself.

      • Thanks Christophe — that was my problem.

        I see the element you referenced in line 4 of your script, above. When I add that back in it displays other SP content we don’t want (the link back home, etc.)

        You said I can choose another anchor / add an element in the CEWP itself. I don’t understand javascript well enough to craft that. Can you please provide an example of a rewritten line 4 that would allow me to get this result?

        Thanks so much!

      • John, you’re correct, the element is called at line 4.

        You could use my favorite technique – try and fail. Create a dummy page, look at the source, and search for everything that says “id=”. Use this id in the script and see what happens.
        Alternately, change the code to this:

        <div id="NewsPlaceholder"></div>
        <script type="text/javascript">   
        var breakingnews = '<span class="ms-sitetitle" style="color:red;"> Note to all users: these are "Breaking News"!</span>';   
        var placeholder = document.getElementById("NewsPlaceholder");   
        var breakingnewstag = document.createElement("span");   
        breakingnewstag.innerHTML = breakingnews;   

        and the news will show up where you put the CEWP.

      • Excellent! Thanks again!

        I wanted the alert to display in the same top-of-the-page area as in your demo. I’d deleted the id you used, and couldn’t identify anything in that area which I could use as the anchor for my alert.

        Followed your try and fail advice until I solved it. I finally added a blank gif in the cell, gave it an id of “alerts” which I called in the script, and — it works. Very, very cool.

        This is for a hospital’s intranet site. When we have an alert, it is usually VERY important. Thanks to this, I now have a way to activate/hide the alert when and wherever I need.

  22. Pingback: A method to customize Web Part zones « Path to SharePoint

  23. This code is great. Question though…I am trying to find code to create a dropdown in sharepoint that, when a user clicks on a certain item in the dropdown, it will open up that file (which is stored on a shared drive). We do not want to upload the files to the SharePoint due to duplication. Is it possible to do this? (I know out-of-the-box SharePoint doesn’t provide this.)

  24. The only problem I am encountering is that I cannot recover the file on a different site collection/server. I can only manage to get it working if it is located underneath the same collection.

    • Sure, you’ll just need to create or find the placeholder for it (see my reply to John Collins).

      For example, try the following change in the code:
      var topleftplaceholder = document.getElementById(‘MSO_ContentTable’);

  25. Christophe, I am successful with CentralScript.txt when in the same site, but the CEWP fails with “The Web Part has timed out” if across sites (using the Content Link field to point to t CentralScript.txt). If I use the “Test Link” button below the Content Link field, I get a blank page whose source is contents of CentralScript.txt – however running the page shows CEWP fails with “The Web Part has timed out.”

    Thinking to eliminate the cross-domain JavaScript issue, I repeated the same using just an .jpg image with the same results.

    I can get CentralScript.txt to work across sites if I remove the first and last line, and include that in the CEWP Source Code editor, but that is less-than-excellent (I will have to make this change to all JavaScripts I use). Here is an example of what DOES work for me in the CEWP Source Code editor:

    As I would prefer to use unmodified JavaScript and the CEWP Content Link field, can you suggest a solution? Do you recognize my symptoms?

    As always, your guidance is greatly appreciated!

    R’grds – Ben.

    • Sorry, lost my example… Please read as: “–script type=”text/javascript” language=”javaScript” src=”http://server.domain.net/mysharepoint/ReusableDocuments/CentralScript.txt”– –/script– (where “–” is greater-than and less-than)

        • Just wondering if BRuiz or Barbara ever found a solution? I am having a similar issue to Barbara’s in that I get the following error when entering the link to the central file: “Cannot retrieve the URL specified in the Content Link property. For more assistance, contact your site administrator.” Like BRuiz, I am successful when linking to CentralScript.txt when in the same site. Wen I use the “Test Link” button below the Content Link field, I get a blank page whose source is the content of CentralScript.txt.

          I am site collection administrator across all site collections. I have ensured that all users have Read permissions to the CentralScript.txt file.


  26. This is how things should work:
    – if anonymous access is enabled for centralscript.txt, you should be able to call it from any page.
    – if the file is accessible to authenticated users only, you should be able to call it from any page within the same site collection.

    If it doesn’t work this way, please let me know and I’ll do some more tests.

    • OK. So I think I missed the Anonymous access part. I will try that and get back to you. Thanks for your patience Christophe.

  27. I love the cross-site menu, you do really nice work. Do you know of a way to security trim the entire menu — i.e., the menu only shows up for people who have a certain permission level?

    • Heather, you could set up permissions on the .txt file. The downside is that people who don’t have access will get a popup asking for credentials.

  28. hello
    its a best practice solution.
    is this a sloution to use multi script in the same CEWP:
    instead of having tow CEWP linked to 2 diff script file, i want to use only one CEWP linked to a script that call the two others

    • hello
      its a best practice solution.
      is this a sloution to use multi script in the same CEWP:
      instead of having tow CEWP linked to 2 diff script file, i want to use only one CEWP linked to a script that call the two others

      • Hi Christophe, there is no probleme with that, but i want to use only one CEWP to save it as a template and re-used elsewhere.

        i have a script library. and one cutomized documentLibrary template that user can add in diffrente sites and many time as needed for each site.
        after adding this Library template we have to add two CEWPs for differente cutomization purpose and link each of them to a script in script library.
        what i did is to combine the tow script in a one script, add it to script library and used it as link in one CEWP and save it as template.
        i was looking to call the tow script from one CEWP
        Thanks Christophe

        • In this case, do the following:
          – instead of txt files, store your scripts as standard script files (.js)
          – instead of using the content link, use the source editor, and use script tags to call your .js files:

          <script src="yourcode.js" type="text/javascript"></script>
  29. thanks Cristophe,
    thats what i tried to use before but it doeasnt work,

    is it because they both use the same jquery library

  30. thanks Cristophe,
    thats what i tried to use before but it doeasnt work,


    is it because they both use the same jquery library

  31. script src=”yourcode1.js” type=”text/javascript
    script src=”yourcode2.js” type=”text/javascript

  32. Hello! I actually implemented this before I found this blog, except I came up with another idea. I wanted to make a function call *after* the body had loaded but *before* the page-load was complete – that way I could alter the text just before it is displayed, which prevents the user from seeing the changes happening. First I attached a css link and a javascript link into the header of my master page. Then, at the end of the master page, right before the closing body tag, I added a little js function call:


    Then, at the top of the linked js file, I find out what the location of the current page is, and using a switch function, if it is one page or another, I set the string variable of RunFuncAtEndOfHTML to the string name of what function I want to call, like this:

    RunFuncAtEndOfHTML = “RunSomeFunction();”

    The function does an eval on the string and thus runs it just before the body tag closes out.
    //This function is placed at the base of the master pages in the PlaceHolderFormDigest id.
    //If you need to call more than one function, create a function to call them all as a batch
    //usage: RunFuncAtEndOfHTML = “whateverfunctionyoulike()”
    function FunctionAtEndOfHTML(whatfunction){eval(whatfunction);}

    And since it is in my master page I don’t have to add or manipulate two CEWPs in every sharepoint page.


  33. Pingback: About Scripts, Web Parts and Urban Myths « Path to SharePoint

  34. hi Christophe,

    This is great – you are my hero – however – do you have the script adjustment to open drop down links in a new window?
    thanks for getting back to me!

    • Sorry Elaine, this reuses a default SharePoint script, and AFAIK there is no such option. You would need to write your own, or find a plugin that does it.

  35. Hi Christophe,

    This solution is great. Now, how could I add more info into the body w/ breaks in between the paragraphs? Also, how could I move/centralized the new custom button to the left or center w/in the same area. I’ve been trying but no luck so far.

    Thanks in advance…

    • Instead of a simple span tag, you’ll need to add a html block with the appropriate formatting. Refer to your usual html guide for the details.

    • You can definitely use this technique in SP 2010! The specific examples posted in this article will not work, but my blog and the User Toolkit have tons of other code samples you can try out.

  36. Has anyone created a version for the 2007 version of:

    var breakingnews = ‘  Note to all users: these are “Breaking News”!’;
    var topleftplaceholder = document.getElementById(“ctl00_PlaceHolderGlobalNavigation_PlaceHolderGlobalNavigationSiteMap_GlobalNavigationSiteMap”);
    var breakingnewstag = document.createElement(“span”);
    breakingnewstag.innerHTML = breakingnews;

    • I should have said create a version for 2010 for the 2007 code:

      var breakingnews = ‘  Note to all users: these are “Breaking News”!’;
      var topleftplaceholder = document.getElementById(“ctl00_PlaceHolderGlobalNavigation_PlaceHolderGlobalNavigationSiteMap_GlobalNavigationSiteMap”);
      var breakingnewstag = document.createElement(“span”);
      breakingnewstag.innerHTML = breakingnews;

  37. Hi Christophe,
    This is a great solution. I want to place this in a master page so I placed a reference to the javascript file in the section and stored the js file centrally but it is not working. I can see the script getting loaded but cannot see the function getting loaded.
    If you have a solution for SP2010 please provide the link to the script.

    • Sorry Anant, this solution was built for SP 2007 and I don’t have an updated version. The structure of the page in SP 2010 is very different so I am not surprised that it doesn’t work.

      • Hi Christophe – is there any chance you can create one for SP2010? I really need to implement this one as I have currently deployed this one in our 2007 environment which will be upgraded in the next couple of months to 2010. It will be really appreciated if you can assist me as I’m not good with javascript. Thanks heaps in advance.

  38. This is awesome. I am deploying your cross site menu in 2010 however it is anchored to the site actions which has moved to the top left. How could I anchor it to the global nav next to the search bar? Thanks for the help.

Comments are closed.