SharePoint Wiki Or Publishing Pages Part 3

To recap from the previous part – the need to use Publishing Pages in my project arose because of the issues I faced using Wiki Pages can be summarized in the following points:-

1)      Problems creating the necessary code generation to routines due to the underlying HTML used by the Wiki Pages.

2)      The difficulty in training the end-users to use Wiki Pages becusae it would require them having to learn about inserting web part components , and configuring the necessary settings related to the individual web part.

3)      Printing issues, printed Wiki content shows up HTML specific content like the Next/Previous links.

To overcome such issues, the alternative was to look into the Publishing Site features of SharePoint which make available a group of Page templates that provide a greater degree of control over the content with embedded web part regions already fixed onto the templates.  You can start to use the publishing pages by either:-

1)      Create a Publishing Site from the Site Settings/Create New Site option and then selecting Publishing Site

2)      Or for an existing site you can harness the publishing pages by going to the Site Settings and from the Manage Site Features option, activate the SharePoint Server Publishing Feature.  This should make available in the Site Settings an option named Page Layouts and Site Templates.

LookAndFeelPageLayouts

When you select that option you should scroll down to the bottom of the page and you will notice under the section named ‘Page Layouts’ the ability to select various Publishing Page Templates as shown below:-

 

 

 

TempaltesSelection

In the screenshot above – you can see that I have selected all the available publishing page template layouts and have also selected a default type which will be selected for me when I want to just use the New Page option from the Site Settings menu.   I will not cover what each and every page layout looks like in this article (you can do this in your own time), but the main ones that we will look into a little in this article are:-

  • Article Page – Image on right
  • Article Page – Summary Links

Also of note is that when you start to use the publishing pages there natural home is a document library named ‘Pages’.  There are a number of default columns available within this document library as shown below:-

PubPagesDocLib

As you can see from the above screenshot – the columns available provide the developer with a greater degree of control regarding what content goes in each column.  I will also add the custom columns that I added for theWiki Page library in Part 2:-

DisplayInContents – this is a Yes/No field and will be used to decide if the page should be listed in the main contents page.

PageNo – this is a numerical field that can be used to assign a page no to the wiki page so that we can use it to control ordering for the wiki pages.

Section – this is a chocie field which I use to assign the Section heading that a wiki page will belong to.  So for instance the page

PrintView – a Yes/No field to indicate that you want the page to appear when creating a view for printing the wiki page library ( more on this later).

Article Page – Image on Right

Now what I want to do is create the main CRM.aspx Content page that will have links to the various CRM related articles.  If you recall from the Wiki Pages article in Part 2 – the contents page for each subject area had an image on the right with a link to the next page under the image, and the main content had links to each of the pages in that subject area. So if we look at the structure of the ‘Image on Right’ article page layout:-

ImageOnRightLayoutPage

Immediately we can realize that the end user who has to create these pages will have a much easier time, as there are place holders on the page layout where they can enter in the necessary key content for the page, with simple point and click areas to add images that are already stored.  The CRM.aspx content page in edit mode looks as follows:-

ImageOnRightCRM

 

Notice in the above screenshot that with publishing pages you can still use Wiki syntax to create links to other pages through use of the square bracket syntax.  The actual published page when viewed normally with have the following appearance:-

 ImageOnRightCRMActual

 Article Page – Summary Links

The Summary links page – layout offers an embedded links web part as shown below:-

SummaryLinksLayout

Again we can say that the user will have a much easier time creating the navigation links to other pages by just using the available menu options on the embedded Summary Links web part.  If we look at how such a page will look normally by using the Customizations.aspx page :-

CustomizationsArticleLinksPage

The look and feel of the above page in many ways has been improved.

Programing to Dynamically Generate Publishing Pages

In the previous part I showed how it was possible to create Wiki Pages programatically and assign the varous property values to each Wiki Page by creating a dictionary object consisting of the page name and property values.  You can do exactly the same with Publishing pages but with more control over the content generation such that you would be silly not to create such publishing pages automatically  if you have many to create using a standard pattern/format.

I will discuss in this section how to create pages with the images, and also the summary links and to begin with I would like to refer you to the original spreadsheet extract shown in part 2:-

 Spreadsheet1

We will use a similar structure to the above but this time will create the other pages for our publishing site on the areas of Oracle and SharePoint as was shown in the original design (for lack of a better word for that diagram J), so the pages we want to create will be based on values in the following spreadsheet:-

 Spreadsheet4

To assist in creating the images we will use the following:-

Spreadsheet5

For some the process may seem long-winded but I have found that controlling the code for the Dictionary lists using spread sheets provides a level of consistency and was in my experience worth the time and effort – I only have to enter in the raw information for columns A, and B – the other columns are simple formula based on the content in columns A and B.

Creating the necessary code required the following setup:-

1)      A console project with project settings as before set for a Target Platform of 64-bit, and utlilizing the .Net Framework 3.5.

2)      Also the DLL reference included a library called Microsoft.SharePoint.Publishing (as well as the standard Microsoft.SharePoint).  Both DLL’s can be found at the same location:-

C:\program files\common files\microsoft shared\web server extensions\14\ISAPI

Once the setup is established the next step is to setup the dictionary objects by taking the necessary code values as generated from the above spread sheets, and copying into the code, and creating the necessary helper methods.  I will in addition to the main Program.cs class file create the following class files:-

MyPubsOrder.cs – this will contain the listing of the page names and the values of their Page Numbers that I want to assign. It will also contain a List object which will contain the page names of the Content page subjects in my design which are Oracle.aspx, and SharePoint.aspx.  The content of this class file is as below:-

public static class MyPubsOrder
{
 public static Dictionary<string, long> myPubsOrder 
                                  = new Dictionary<string, long>(){
    {"Oracle",20},
    {"Oracle SQL",21},
    {"Oracle PLSQL",22},
    {"Database Admin",23},
    {"SharePoint",30},
    {"EventHandlers",31},
    {"Visual Web Parts",32},
    {"Content Types",33}
 };

 public static List<string> myPubsContentPages = new List<string>(){
   "Oracle",
   "SharePoint"
 };
}

CreateSummaryLink.cs – this file is based on information I found by studying the underlying HTML generated after creating the Summary Links:-

NextPrevLinksSummaryPage

 

So in this class file I want to create a constant that holds the HTML to create the Navigation HTML,  and also a helper method to apply the underlying URL that the Next and Previous links will navigate to.  The class file looks as follows:-

public static class CreateSummaryLink
 {
 const string NextLinkP1 = "<div title=\"_schemaversion\" id=\"_3\">" +
 "<div title=\"_links\">" +
 "<div title=\"_link\">" +
 "<span title=\"_title\">Navigation</span>" +
 "<span title=\"_order\">1</span>" +
 "<span title=\"_begincolumn\">True</span>" +
 "<span title=\"_isgroupheader\">True</span>" +
 "<span title=\"_groupstyle\">Band</span>" +
 "</div>" +
 "<div title=\"_link\">" +
 "<span title=\"_title\">Next</span>" +
 "<span title=\"_order\">2</span>" +
 "<span title=\"_begincolumn\">False</span>" +
 "<span title=\"_group\">Navigation</span>" +
 "<span title=\"_linkurl\">";
const string NextLinkP2 = "</span>" +
 "<span title=\"_style\">Default</span>" +
 "</div>";
const string PrevLinkP1 = "<div title=\"_link\"><span title=\"_title\">" + 
                       "Previous</span><span title=\"_order\">3</span>" +
                       "<span title=\"_begincolumn\">False</span>" +
                       "<span title=\"_group\">Navigation</span>" +
                       "<span title=\"_linkurl\">";
const string PrevLinkP2 = "</span><span title=\"_style\">Default</span>"+
                          "</div></div><div title=\"_view\">" +
                          "<span title=\"_columns\">2</span>"+
                          "<span title=\"_linkstyle\">Default</span>" +
                          "<span title=\"_groupstyle\">Band</span>" +
                          "</div></div>";
/// <summary>
 /// Gets the HTML to create the summary links [Next] 
 /// and [Previous] for the page.
 /// </summary>
 /// <param name="nextLinkPage">Base Name of the Next Page</param>
 /// <param name="prevLinkPage">Base Name of the Previous Page</param>
 /// <returns></returns>
 public static string GetSummaryLinkHTML
      (string nextLinkPage, string prevLinkPage)
 {
  string summaryHTML = string.Empty;
  nextLinkPage = nextLinkPage.Replace(" ", "%20") + ".aspx";
  prevLinkPage = prevLinkPage.Replace(" ", "%20") + ".aspx";
  string urlNextLink = "/MyPubSite/Pages/" + nextLinkPage;
  string urlPrevLink = "/MyPubSite/Pages/" + prevLinkPage;
  string urlNextLinkA = "<a href=\"" + urlNextLink + "\">" + 
                         urlNextLink + "</a>";
  string urlPrevLinkA = "<a href=\"" + urlPrevLink + "\">" + 
                         urlPrevLink + "</a>";
  summaryHTML = NextLinkP1 + urlNextLinkA + NextLinkP2 + 
                PrevLinkP1 + urlPrevLinkA + PrevLinkP2;
  return summaryHTML;
 }
}

NextPrevLinksSetup.cs – this class file I have a mixture of Dictionary objects and helper methods to create the Next/Previous Links, to place the images on the contents page and also to add the necessary Next  Previous links under the images in the Image caption area for the Contents pages (i.e. in our example it will be for the Oracle.aspx page, and SharePoint.aspx pages).    The content of this class is as follows:-

public static class NextPrevLinksSetup
{
 public class NextPrev 
 {
 public string Next {get; set;}
 public string Prev {get; set;}
 public NextPrev(string next, string prev)
  {
   this.Next = next;
   this.Prev = prev;
  }
 }
public static string GetImageLink(string pageBaseName)
 {
 string imageLink = string.Empty;
 string imageFileName = string.Empty;
 if (NextPrevLinksSetup.PageImageLinks.TryGetValue
    (pageBaseName, out imageFileName))
 { 
   imageLink = "<img alt=\"\" src=\"/MyPubSite/PublishingImages/" + 
              imageFileName + "\" style=\"border:7px solid\" />";
 } 
 return imageLink;
 }

public static Dictionary<string, string> PageImageCaptions 
                     = new Dictionary<string, string>()
{
 {"Oracle","[[Reports|Previous]] | [[Oracle SQL|Next]]"},
 {"SharePoint","[[Database Admin|Previous]] | [[EventHandlers|Next]]"}
};
public static Dictionary<string, string> PageImageLinks 
                     = new Dictionary<string, string>()
{
 {"Oracle","Oracle.png"},
 {"SharePoint","SharePoint.png"} 
};
public static Dictionary<string, NextPrev> PagesNextPrevLinks 
                     = new Dictionary<string, NextPrev>()
{
 {"Oracle", new NextPrev("Oracle SQL","Reports")},
 {"Oracle SQL", new NextPrev("Oracle PLSQL","Oracle")},
 {"Oracle PLSQL", new NextPrev("Database Admin","Oracle SQL")},
 {"Database Admin", new NextPrev("SharePoint","Oracle PLSQL")},
 {"SharePoint", new NextPrev("EventHandlers","Database Admin")},
 {"EventHandlers", new NextPrev("Visual Web Parts","SharePoint")},
 {"Visual Web Parts", new NextPrev("Content Types","EventHandlers")},
 {"Content Types", new NextPrev("CRM","Visual WebParts")}
};
}

Note that I have uploaded the image files into the PublishingImages folder in my SharePoint site.

With these class files setup we can begin the creation of the necessary code to generate our publishing pages.  Now before this is presented – you will notice in the code that there is a line which requires that the appropriate article page is selected depending on if we want to create a page with an image (for our subject contents page) or if we want to just create a normal page with the summary links embedded web part.  The logic to decide this in the code below is done by selecting the appropriate entry in the “PageLayouts” array.  The layouts are listed within this array based on their positional ordering within the Page Layouts and Templates page that is accessed through the publishing site settings, so in our scenario based on the illustration below:-

PageLayoutsOrdering

We can say that:-

(Article Page) Body Only = 0

(Article Page) Image on Left = 1

And so on…

So for our implementation the image on right template will be in position 2 and the summary links page is in position 3.  With this in mind here is the code (you will need to supply to include the using statements – references to Microsoft.SharePoint AND also Microsoft.SharePoint.Publishing):-

public static void CreatePublishingPages()
{
 using (SPSite site = new SPSite("http://{site:port}/MyPubSite"))
 {
  using (SPWeb web = site.OpenWeb("MyPubSite"))
  {
   web.AllowUnsafeUpdates = true; 
   SPList oPubList = web.Lists["Pages"];
   PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web);
   PageLayout[] layouts = publishingWeb.GetAvailablePageLayouts(); 
   // first create the content pages using the (Article Page) 
   // Image on right layout
   foreach(KeyValuePair<string, long> pair in MyPubsOrder.myPubsOrder)
   {
    //set the page layout for the html page...
    string summaryLink = string.Empty;
    string summaryImage = string.Empty;
    Boolean IsContentsPage = false;
    PageLayout layout = null;
    string pageBaseName = pair.Key;
    if (MyPubsOrder.myPubsContentPages.Contains(pair.Key))
    {
     // assumes image on right page layout is second in list
     layout = layouts[2];
     summaryImage = NextPrevLinksSetup.GetImageLink(pageBaseName);
     IsContentsPage = true;
    }
    else
    {
     // assumes summary link page layout is third in the list
     layout = layouts[3];
     // set the publishing links 
     NextPrevLinksSetup.NextPrev theLinks;
     if (NextPrevLinksSetup.PagesNextPrevLinks.TryGetValue
          (pageBaseName, out theLinks))
     {
       summaryLink = CreateSummaryLink.GetSummaryLinkHTML(
          theLinks.Next, theLinks.Prev);
     }
    }
    string pageName = pageBaseName + ".aspx";
    PublishingPage newPage = 
               publishingWeb.GetPublishingPages().Add(pageName, layout);
    newPage.Title = pageBaseName;
    // add other document library properties
    SPListItem newPageItem = newPage.ListItem;
    if (IsContentsPage)
    {
     newPageItem["DisplayInContents"] = "Yes";
     if (NextPrevLinksSetup.PageImageCaptions.ContainsKey(pageBaseName))
     {
      string captionContent = string.Empty;
      NextPrevLinksSetup.PageImageCaptions.TryGetValue
                (pageBaseName, out captionContent);
      newPageItem["PublishingImageCaption"] = captionContent;
     }
    } 
    newPageItem["PageNo"] = pair.Value.ToString(); 
    newPageItem["ArticleByLine"] = "Publishing Page Testing"; 
    newPageItem["PublishingPageContent"] = 
                   "Custom Content for Page to Go Here....";
    // additional content for summary links to be added 
    if (!string.IsNullOrEmpty(summaryLink))
    {
      newPageItem["SummaryLinks"] = summaryLink;
    }
    if (!string.IsNullOrEmpty(summaryImage))
    {
      newPageItem["PublishingPageImage"] = summaryImage;
    }
    newPageItem.UpdateOverwriteVersion();
    Console.WriteLine("Publishing Page Added"); 
   }
  }
 }
}

The type of output that can be achieved from the above is illustrated in the following screenshots:-

OracleContentsPage

 

Above is a screenshot of the subject contents page – and is based on the Article Page – Image on Right layout.  We have as listed in the code added in the image caption area links to the Previous and Next pages by applying the normal control sequences used in Wiki Pages for linking.  Below is the sample output based on the Article Page – Summary Links layout for a normal content page:-

OracleSQLPage

As you can see from the above – the Navigation links have created based on the Dictionary classes that were defined.  You may have noticed that the actual content has nothing much useful – this is something you can do later or apply in the main routine above by reading content from a different source such as a Word document or text file.  In my case the situation was a little complicated as all my content (over 100 pages) was within my first attempt using Wiki Pages.  Therefore I had to read in from the wiki pages the content by parsing the underlying HTML contained in the WikiField column and copying to the PublishingPageContent column.  Now to do this I had to make use of something called the HTMLAgilityPack which you can download from CodePlex – the code within that library made it easier for me to extract the relevant HMTL that contained the text content.  Also of interest to you is that if you want to update a publishing page after it is created then you can use the following code:-

private static void UpdatePageProperty(string pageID, 
           Dictionary<string, string> propVals)
 {
 SPService.Lists listService = new SPService.Lists();
 listService.Credentials= System.Net.CredentialCache.DefaultCredentials;
 if (propVals.Count > 0)
 {
  StringBuilder strBatch = 
        new StringBuilder("<Method ID='1' Cmd='Update'><Field Name='ID'>" +
            pageID + "</Field>");
  foreach (KeyValuePair<string, string> pair in propVals)
  { 
   strBatch.Append("<Field Name='" + pair.Key + "'>" 
                   + pair.Value + "</Field>"); 
  }
  strBatch.Append("</Method>");
  XmlDocument xmlDoc = new System.Xml.XmlDocument();
  System.Xml.XmlElement elBatch = xmlDoc.CreateElement("Batch");
  elBatch.SetAttribute("OnError", "Continue");
  elBatch.SetAttribute("ListVersion", "1");
  elBatch.SetAttribute("ViewName", "");
  elBatch.InnerXml = strBatch.ToString();
  XmlNode ndReturn = listService.UpdateListItems("Pages", elBatch);
  Console.WriteLine(ndReturn.OuterXml);
 }
}

Note that the above code requires that you supply a PageID value – this is the underlying “ows_ID” value for the published page within the Pages document library.  You should be able to retrieve this value by carrying out a search using the BaseName of the page.

Printing Publishing Pages

Now in terms of printing – if we use the same approach we used in the previous part with Wiki Pages which was to assign the property PrintView with ‘Yes’ values for the pages we want to show (I have as in the previous example selected the CRM related pages :- CRM.aspx, Customizations.aspx, Marketing Lists.aspx), we get the following output:-

PublishingPagePrintViewWithoutImage

As can be seen from above there is no longer any image being displayed or the Next/Previous links that we have created.    To create the above view – I made the following selections:-

-          Only the Page Content column was selected

-          Sorting was done by the PageNo property

-          Filtering was based on selecting where PrintView = “Yes”, AND Section=”Software”

I now have greater control over what gets shown in this Printing view, so if I do want to show my image on the main contents page – all I have to do is select the Page Image column in the view, which would give me the the following output:-

PublishingPagePrintViewWithImage

Finishing Touches Which You will want to Consider

I mentioned in the previous part that there are printing issues with Web Part generated content such as the output from a Content Query web part used in the previous section to create an overall Contents Page.  To overcome this issue – I did the following:-

  1. Created a Main Body Article page
  2. Created a Visual Web Part that consisted of a button, which when clicked would generate output which would be the Contents of the entire publishing site in a format that the users wanted, which meant that it had links to each publishing page.  The output would be placed into the Body of the page created in point (1).  The code to generate the contents page is very simple in that all it does is go through the Pages document library, and creates headings based on Section names, and orders the links based on the PageNo values.  Also entries only go into the page if the DisplayInContents value is ‘Yes’.
  3. I created a web part page – which would host my Visual Web Part button, and this page would be like an administrators page where they could re-generate the contents page as new publishing pages are added to the site.

For the user experience – it is always good to provide a way of quick navigation, so the left hand menu was something I amended to be the fly-out type, this can easily be accomplished by creating the master page and changing a single setting (please look this up for yourself).  The fly-out menu I did consisted of menu options for each ‘Section’ heading type, which when selected would display the main Content pages for that Section heading.  Again I developed a Visual Web Part button which generated the links to be associated with the fly-out menu Section Headings.

Be aware also that having read around various blogs – you are also able to add to the existing Publishing Page Layouts using SharePoint Designer 2010. However, that is something for another time !!!  Finally I just want to say thank you to all those bloggers out there, and people who have contributed to this area of SharePoint because I had a lot of assistance from them when I ran into problems.  If I could go back in time I would have kept the URL of those links so that I could out of respect provide links to their sites, apologies for my failure on this matter.

SharePoint Wiki Or Publishing Pages Part 2 <<<

SharePoint Wiki Or Publishing Pages Part 1 <<<

SharePoint Wiki Or Publishing Pages Introduction <<<

 

 

:

2 Responses to “SharePoint Wiki Or Publishing Pages Part 3”

  1. Excellent website. Lots of useful info here. I’m sending it to a few pals ans additionally sharing in delicious. And obviously, thank you on your effort!

  2. Hi my friend! I want to say that this article is amazing, nice written and come with approximately all vital infos. I would like to see extra posts like this .

Leave a Reply