Showing posts with label Publishing. Show all posts
Showing posts with label Publishing. Show all posts

11 May 2009

How to detect when a SharePoint Publishing Page is detached from it's PageLayout

Recently I found a new thing about SharePoint Publishing pages. From within SharePoint Designer, publishing pages can be detached from there pagelayout!

I guess that for some of you this not a a new thing, but I didn't know.

In a normal publishing senario this is also not a common thing to do, because the page is disconnected from the pagelayout and changes to the pagelayout will no longer affect the page. But in certain situations it can be usefull, like using SharePoint Designer to place webparts on a publishing page. Normaly this can only be done from the browser interface. Of course a page can also be attached to a pagelayout again.

To detach a page in SharePoint designer, open the Pages list and right click on the page.


Now you get a dialog 'Detaching from the page layouts http:/xxxx/_catalogs/masterpage/xxxx.aspx will copy its markup into this page, where it can be customized. Changes to the pagelayout will no long affect this page.'

To reattach a page to it's pagelayout, right click on the page again.


After knowing how to detach a page from it's pagelayout, I wanted to find out how a publishing page would know it was detached and after some investigation I found that this information is stored in the listitem for the page. Each publishing page has a field called 'PublishingPageLayout' and this field normaly contains the url of the pagelayout and the name of the content type.
Value format: 'http://xxxx/catalogs/masterpage/xxxx.aspx, ContentTypeName'

But after detaching the pagelayout this field contains another kind of information. Namely an indication that the page is a disconnected publishing page and a reference to the pagelayout is once was connected to.
Value format: 'http://www.microsoft.com/publishing?DisconnectedPublishingPage=true, http://xxxx/_catalogs/masterpage/xxxx.aspx

To detect all disconnected publishing pages in a site collection I created a the following code:
using (SPSite site = new SPSite("http://demosite"))
{
    SPWeb rootWeb = site.RootWeb;

    // Query to get all publishing pages in the sitecollection that are detached from pagelayout.
    // ServerTemplate=850, is template for the Pages lists.
    SPSiteDataQuery dataQuery = new SPSiteDataQuery();
    dataQuery.Webs = "< Webs Scope="SiteCollection">";
    dataQuery.Lists = "< Lists ServerTemplate="850">";
    dataQuery.ViewFields = "< FieldRef Name="FileRef" Nullable="TRUE">";
    dataQuery.Query = "< Where>" +
                            "< Contains>" +
                                "< FieldRef Name="PublishingPageLayout">" +
                                "< Value Type="Text">?DisconnectedPublishingPage=true< /Value>" +
                            "< /Contains>" +
                        "< /Where>";                              

    // Store result in datatable
    DataTable dt = rootWeb.GetSiteData(dataQuery);
    foreach (DataRow row in dt.Rows)
    {
        if (row.IsNull("FileRef"))
        {
            Console.WriteLine("FileRef should not be null!");
            continue;
        }

        // Strip listitem id from fieldref value
        string fieldRef = row["FileRef"].ToString().Trim();
        if (!string.IsNullOrEmpty(fieldRef))
        {
            int pos = fieldRef.IndexOf(";#");
            if (pos > -1)
            {
                fieldRef = fieldRef.Substring(pos + 2);
            }
        }

        Console.WriteLine(fieldRef);
    }
}          
Also you can use the 'Content and Structure Reports' functionality from MOSS to get an overview of all publishing pages that are disconnected from the pagelayout.

To do this, go to the 'Content and Structure Reports' list inside to root site. Create a new item and fill the field like below.
  • Report Title: All Pages Disconnected from PageLayout
  • Resource Id: (leave blank)
  • Resource Id: (leave blank)
  • CAML List Type: <Lists ServerTemplate='850' />
  • CAML Query: <Where><Contains><FieldRef Name='PublishingPageLayout' /><Value Type='Text'>?DisconnectedPublishingPage=true</Value></Contains></Where>
  • Target Audiences: (leave blank)
  • Report Description: All publishing pages that are detached from their pagelayout by using SharePoint Designer.



Afer creating a new report, you can access it through the Site Actions button.

24 March 2009

Understanding Field Controls and Web Parts in SharePoint Server 2007 Publishing Sites

I just read an great article from Andrew Connell about the use of Field Controls and Web Parts in MOSS 2007 Publishing sites.

He describes clearly the advantages and disadvantages of using them and that you should considered in the early phase of the implementation of a new publishing site which approach to use.

Read the article on MSDN
Understanding Field Controls and Web Parts in SharePoint Server 2007 Publishing Sites.

15 March 2009

SharePoint PublishingWeb class inside out

For a project I've done in the past, I had to create an application that could report all sorts of SharePoint site information. While developing this application, the biggest challenge was to gather information about publishing sites, without the use off the Micosoft.SharePoint.Publishing assembly. The reason for this was that the application also had to run on a WSS only installation of SharePoint. During refactoring I found out that most information was stored in the propertybag of the web.

I created a SharePoint Publishing helper class that can retrieve values for the following PublishingWeb properties and functions.
  • GetAvailablePageLayouts
  • GetIncludeInNavigation
  • IncludeInCurrentNavigation
  • IncludeInGlobalNavigation
  • IncludePagesInNavigation
  • IncludeSubSitesInNavigation
  • InheritAlternateCssUrl
  • InheritCurrentNavigation
  • InheritCustomMasterUrl
  • InheritGlobalNavigation
  • IsInheritingAvailablePageLayouts
  • IsInheritingAvailableWebTemplates
  • IsPublishingWeb
  • NavigationAutomaticSortingMethod
  • NavigationShowSiblings
  • NavigationSortAscending
  • OrderingMethod
  • PagesListId
public static class SharePointPublishingHelper
{
 public static bool IsPublishingWeb(SPWeb web)
 {
  return GetBooleanValueFromPropertyBag(web, "__PublishingFeatureActivated", false);
 }

 public static bool IncludeInGlobalNavigation(SPWeb web)
 {
  return GetIncludeInNavigation(web, "__GlobalNavigationExcludes");
 }
 
 public static bool IncludeInCurrentNavigation(SPWeb web)
 {
  return GetIncludeInNavigation(web, "__CurrentNavigationExcludes");
 }
 
 private static bool GetIncludeInNavigation(SPWeb web, string propertyKey)
 {
  if(web == null)
  {
   throw new ArgumentNullException("web");
  }
  if (string.IsNullOrEmpty(propertyKey))
  {
   throw new ArgumentException("The argument can't be null or a empty string.", "propertyKey");
  }
 
  SPWeb parentWeb = web.ParentWeb;
  if (!web.IsRootWeb && parentWeb != null)
  {
   string globalNavigationExcludes = GetValueFromPropertyBag(parentWeb, propertyKey) as string;
   if (!string.IsNullOrEmpty(globalNavigationExcludes))
   {
    string[] list = globalNavigationExcludes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
    bool found = list.Contains(web.ID.ToString("D"));
 
    return !found;
   }
  }
 
  return true;
 }
 
 public static bool InheritGlobalNavigation(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  if (web.IsRootWeb)
  {
   return false;
  }
 
  return web.Navigation.UseShared;
 }
 
 public static bool InheritCurrentNavigation(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  if (web.IsRootWeb)
  {
   return false;
  }
 
  return GetBooleanValueFromPropertyBag(web, "__InheritCurrentNavigation", true);
 }
 
 public static bool IncludeSubSitesInNavigation(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  return GetBooleanValueFromPropertyBag(web, "__IncludeSubSitesInNavigation", true);
 }
 
 public static bool IncludePagesInNavigation(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  return GetBooleanValueFromPropertyBag(web, "__IncludePagesInNavigation", true);
 }
 
 public static string OrderingMethod(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  string value = GetValueFromPropertyBag(web, "__NavigationOrderingMethod").ToString();
  switch (value)
  {
   case "0":
    return "Automatic";
   case "1":
    return "ManualWithAutomaticPageSorting";
   case "2":
    return "Manual";
   default:
    break;
  }
 
  return "Manual";
 }
 
 public static bool NavigationShowSiblings(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  if (web.IsRootWeb)
  {
   return false;
  }
 
  return GetBooleanValueFromPropertyBag(web, "__NavigationShowSiblings", true);
 }
 
 public static string NavigationAutomaticSortingMethod(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  string value = GetValueFromPropertyBag(web, "__NavigationAutomaticSortingMethod").ToString();
  switch (value)
  {
   case "0":
    return "Title";
   case "1":
    return "CreatedDate";
   case "2":
    return "LastModifiedDate";
   default:
    break;
  }
 
  return "Title";
 }
 
 public static bool NavigationSortAscending(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  return GetBooleanValueFromPropertyBag(web, "__NavigationSortAscending", true);
 }
 
 public static Guid PagesListId(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  string value = GetValueFromPropertyBag(web, "__PagesListId").ToString();
  if (string.IsNullOrEmpty(value))
  {
   return Guid.Empty;
  }
 
  return new Guid(value);
 }
 
 public static bool InheritCustomMasterUrl(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  return GetBooleanValueFromPropertyBag(web, "__InheritsCustomMasterUrl", false);
 }
 
 public static bool InheritAlternateCssUrl(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  return GetBooleanValueFromPropertyBag(web, "__InheritsAlternateCssUrl", false);
 }
 
 public static bool IsInheritingAvailableWebTemplates(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  return GetBooleanValueFromPropertyBag(web, "__InheritWebTemplates", false);
 }
 
 public static bool IsInheritingAvailablePageLayouts(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  string value = GetValueFromPropertyBag(web, "__PageLayouts").ToString();
  if (!string.IsNullOrEmpty(value))
  {
   return value.Equals("__inherit", StringComparison.InvariantCultureIgnoreCase);
  }
 
  return false;
 }
 
 public static string[] GetAvailablePageLayouts(SPWeb web)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
 
  List list = new List();
 
  string value = GetValueFromPropertyBag(web, "__PageLayouts").ToString();
  if (!string.IsNullOrEmpty(value))
  {
   SPWeb rootWeb = web.Site.RootWeb;
 
   var pageLayouts = XElement.Parse(value).Elements("layout");
   foreach (var pageLayout in pageLayouts)
   {
    string itemUrl = null;
 
    string id = null;
    XAttribute guidAttribute = pageLayout.Attribute("guid");
    if (guidAttribute != null)
    {
     id = guidAttribute.Value;
    }
 
    // first try to find pagelayout by id
    if (!string.IsNullOrEmpty(id))
    {
     SPFile file = rootWeb.GetFile(new Guid(id));
     if (file != null && file.Exists)
     {
      itemUrl = file.ServerRelativeUrl;
     }
    }
 
    // if no pagelayout is found by id, try the url
    if (string.IsNullOrEmpty(itemUrl))
    {
     string url = null;
     XAttribute urlAttribute = pageLayout.Attribute("url");
     if (urlAttribute != null)
     {
      url = urlAttribute.Value;
     }
 
     SPFile file = rootWeb.GetFile(url);
     if (file != null && file.Exists)
     {
      itemUrl = file.ServerRelativeUrl;
     }
    }
 
    if (!string.IsNullOrEmpty(itemUrl))
    {
     list.Add(itemUrl);
    }
   }
  }
 
  return list.ToArray();
 }
 
 private static object GetValueFromPropertyBag(SPWeb web, string key)
 {
  if (web == null)
  {
   throw new ArgumentNullException("web");
  }
  if (string.IsNullOrEmpty(key))
  {
   throw new ArgumentException("The argument can't be null or a empty string.", "key");
  }
 
  object value = null;
 
  // First check the AllProperties collection
  if (web.AllProperties.ContainsKey(key))
  {
   value = web.AllProperties[key];
  }
 
  // Still empty, check also the Properties collection
  if (value == null)
  {
   if (web.Properties.ContainsKey(key))
   {
    value = web.Properties[key];
   }
  }
 
  return value;
 }
 
 private static bool GetBooleanValueFromPropertyBag(SPWeb web, string key, bool defaultValue)
 {
  string value = GetValueFromPropertyBag(web, key) as string;
 
  bool ret;
  if (!bool.TryParse(value, out ret))
  {
   ret = defaultValue;
  }
 
  return ret;
 }
}