Posted on:
Categories: SharePoint;CodePlex
Description:
​I'm currently working on a project for a client that requires some extra pages in the My Sites portal. These pages are an extension of user's profile, and need to be visible to all users when viewing all the user profiles. So, to make these available to all users you would just go into the site's Quick Launch settings and then just add some new headings or links. Everything looks good when you are viewing your own user profile, the links appear in the left navigation as you'd expect under "About" and "Newsfeed". When you go to look at someone else's profile though, all your newly added links disappear. This is with both the out of the box master page, and with a custom one. After testing a few other things to try and isolate or work around the issue (e.g. Adding links as the farm account or the application pool account) nothing seemed to work, so I had to create a support ticket with Microsoft. It didn't take longer than an hour to be able to have Microsoft reproduce this issue, and after some back and forth I was informed that this is being acknowledged as a bug and that there currently is no workaround for it and because it is newly discovered there isn't an ETA on a hotfix. Because of my client's need for having these extra pages available in the navigation for all their users I had to come up with a workaround. To do this, I decided that JavaScript could be leveraged to add the required navigation links. For this I created a new SharePoint 2013 Farm Solution (the included JavaScript could be used in a SandBoxed solution as well, but I wanted to use a UserControl so I could generate the menu options and HTML in C# and just use the JavaScript to add the HTML to the navigation). The SharePoint solution looks like the following (you can download the solution from CodePlex - link at the bottom) So for a brief overview of the elements SLMySitesNavInjectionUserControl - Contains all the logic that generates the required HTML for the new menu items and adds all the required JavaScript and JavaScript include files to the current page jquery-1.10.1.min.js - jQuery library include (you could switch to the newer 2.0 library if you wanted, but I required IE8 support still) SLMySitesNavInjection.js - JavaScript that actually adds the HTML items generated by the User Control to the Left Navigation on the page MySitesNavInjectionControlRegistration - an empty SharePoint element that contains the control registration to add the SLMySitesNavInjectionUserControl to the site Definitions.cs - internal static class containing constants (e.g. include files, HTML templates...) used in the solution UlsHelper.cs - a static class containing some useful methods for writing to the SharePoint ULS log So for ease of implementation, and to keep it all simple, all the links that are to be added to the site are managed in a 2-dimensional array in the Definitions.cs file internal static readonly string[,] ProfilePageLinks = new[,] "/mypage1.aspx", "Page 1", "/mypage2.aspx", "Page 2", "/mypage3.aspx", "Page 3" ; To add or remove links you just need to manage the items in this array (I know there are a number of better options to make this more manageable with out requiring a WSP update on the farm, but I'm really hoping this is temporary and that Microsoft will have this all fixed in a future CU). After you've updated this array with all your links all you need to do to get this solution working on your My Site Portal is Package the solution as a WSP Deploy the WSP to your SharePoint 2013 Farm Navigate to your My Site Portal and activate the included Site Feature "SL My Sites Nav Injection Feature" Now you should see your specified links all the time in the left navigation. Note - there are some limitations though. The way this is built the links won't be added to user's personal sites (e.g. SkyDrive Pro, blog, ...) just to the user profiles site. To download this solution from CodePlex go here http//sp2013mysitesnavinjection.codeplex.com/




Posted on:
Categories: SharePoint
Description:
​When creating custom master pages for SharePoint 2013 it's nice to be able to use it with many site templates (e.g. Publishing sites, Search and possibly Team sites. As compared to previous versions of SharePoint you usually needed a unique master page for each usage scenario. While working with a custom master page, I ran into a weird issue when testing it with some Team sites. When using structural navigation for the left navigation (Quick Launch) I noticed with the custom master page the left navigation was blank. I switched the master page back to Seattle.master and all my expected navigation items showed back up. This was even more confusing because our custom master page was fairly similar to the default Seattle.master file. After further testing I was able to at least determine the master page element that was at fault as we as two workarounds for the issue Enable the SharePoint Server Publishing Infrastructure Feature (Site Collection Scoped) Change the SiteMapProvider for the Left Navigation So, if you look at the code snippet below from the master page you'll see highlighted the default SiteMapProvider that is being used. <aspSiteMapDataSource ShowStartingNode="False" SiteMapProvider="SPNavigationProvider" id="topSiteMap" runat="server" StartingNodeUrl="sid1002"/> For some reason when using a custom master page on Team sites, the SPNavigationProvider doesn't return any links configured in the Quick Launch settings (even Lists and Libraries set to show on Quick Launch or even links/headings you manually added). It appears that the SPNavigationProvider provider is dependent on the SharePoint Publishing and when you use the out of the box master pages with a team site there is either a delegate control injected that overrides the SiteMapProvider that is embedded in the master page (SPNavigationProvider) or there's another site/web property that I'm not aware of that enables the Quick Launch to work properly. So for solution 1, if you are ok with all the extra libraries and lists created, than you can just enable the SharePoint Server Publishing Infrastructure Feature (Site Collection Scoped) . The left navigation will then appear exactly as it does in the Navigation settings as it's now using Current Navigation instead of Quick Launch. Solution 2 doesn't require any site structure changes, but it does require a minor change to your custom master page. If you change the SiteMapProvider from SPNavigationProvider to CurrentNavigation the Quick Launch navigation will properly appear. <aspSiteMapDataSource ShowStartingNode="False" SiteMapProvider="CurrentNavigation" id="topSiteMap" runat="server" StartingNodeUrl="sid1002"/> This change will also work for Publishing sites as well, so if you are doing a single custom master page for both Publishing and Team sites this solution would work.




Posted on:
Categories: SharePoint
Description:
While doing a SharePoint 2010 to 2013 upgrade you might run into situations where you would like to automate the upgrade process a bit. I've worked with numerous SharePoint 2010 deployments that contain a number of customizations that will require a lot of manual work to switch everything over to 2013. For example, if you are dealing with a large Intranet that has a highly customized look and feel via branding (Master Pages, Page Layouts and Cascading Style Sheets), and then add in hundreds (or perhaps thousands) of pages that contain custom Web Parts spread over numerous site collections, you probably don't feel like manually switching everything over to their new SharePoint 2013 equivalents. This is where some custom utilities could come in handy. As you might know, SharePoint 2013 allows you to host SharePoint 2010 Site Collections without having to do much work besides a database attach to a Web Application and ensuring all the required custom solutions (WSP's) are deployed (that's definitely not all that's involved for a successful upgrade but it's enough for this overview). So for upgrading your current farm to SharePoint 2013 it's not a huge undertaking if you are happy leaving your Site Collection(s) in SharePoint 2010 mode. If you are looking to take advantage of all the newer features though, you'll want to eventually upgrade those Site Collections to 2013 mode. I'm not going to go into too much detail here what the advantages/changes are of SharePoint 2013 over 2010, but some of the ones I was looking to leverage are Better branding implementation (ability to better leverage HTML5 and CSS3) Channel Management (to better target mobile and tablets) .Net 4.0 for Web Parts and other custom solutions While I was in the process of updating all the custom solutions to SharePoint 2013, I ran into some minor issues when actually updating everything in the Site Collection. When you upgrade a site collection you usually will just open up the SharePoint 2013 Management Shell and run the following cmdlet Upgrade-SPSite -ID http//siteurl -VersionUpgrade This will start upgrading your Site Collection from 2010 to 2013 mode. This is quite handy, but I was running into an issue about the order of doing things, and I wanted it more streamlined for this update. When you upgrade your Site Collection to 2013 mode, SharePoint also will set all your default channel settings (these are stored in a file called __DeviceChannelMappings.aspx that is stored in the Master Page Gallery for your Site Collection. There isn't much documentation on this file, but if you look at the source code of the file you'll see all the channel defaults are configured to the Master Pages and Alternate CSS settings you had when you performed the upgrade. I wanted to be able to automate the removal of the custom 2010 branding and apply the new 2013 branding all in one pass. This would allow me to remove all the unused assets and other elements such as the custom Content Types for the publishing page layouts, unfortunately, due to the default channel mappings set up my code wasn't able to remove the old Master Pages because they were being referenced by the __DevinceChannelMappings.aspx file. I could have gone in and manually configured the channel settings to the new Master Pages, and then deleted the files, but then I'd have to do this on every Site Collection (I know, I could write a couple different console applications to do each series of changes between all the manual configuration steps, but I prefer to get as much done in a single pass as possible). To get around this, I decided it would be better to do the Site Collection upgrade in code while the branding changes were being applied. This allowed for a single console application to Deactivate the old 2010 Branding Upgrade the Site Collection to 2013 mode Apply the new 2013 Branding Switch all page layouts from the 2010 versions to the new 2013 versions Remove all the 2010 branding assets and other related elements So I attempted to use the SPSite.Upgrade() method that has been added in 2013, and then just monitor the upgrade status and site schema version to determine if the upgrade was completed (SPSite.SchemaVersion and SPSite.UpgradeInfo properties). Unfortunately this didn't seem to do the trick. From looking at the ULS logs, it appears that the SPSite.Upgrade() call was trying to upgrade the Site Collection to the target template version of 14.0.0.3, which it was already at, so no upgrade process was starting. So with the only roadblock still was upgrading the site collection to 2013 mode in my utility app I fell back on leveraging reflection to see if there was another way to do this. Note Use this at your own risk because this isn't supported by Microsoft and things could change after a Cumulative Update. So in the SPSite class I discovered a set of methods called StartUpgrade. There was a few instances of that method with different signatures, but I used this one for my situation internal void StartUpgrade(SPSiteUpgradeType upgradeType, bool queueOnly) So in your code you will want to include a reference to System.Reflection and then you could use the following method to do a synchronous upgrade on your Site Collection. private static void UpgradeSiteCollection(SPSite site, Logger logger) if (site.SchemaVersion.Major < 15) var siteType = typeof (SPSite); Type[] paramTypes = typeof (SPSiteUpgradeType), typeof (bool) ; object[] parameters = SPSiteUpgradeType.VersionUpgrade, false ; var methodStartUpgrade = siteType.GetMethod("StartUpgrade", BindingFlags.NonPublic | BindingFlags.Instance, null, paramTypes, null); if (methodStartUpgrade != null) methodStartUpgrade.Invoke(site, parameters); As SharePoint 2013 continues to mature the documentation on the additions to the SharePoint Object Model should expand. Hopefully there'll be some documentation on how to properly do a Site Collection upgrade via the object model without having to rely on using a workaround like this.