As I said earlier, I’ve been playing with WSS as a blogging platform, and one thing I wanted that I could find was a web part which displayed the top 5 latest posts across the entire site.
So, I set about writing one to do the job (source code).
Now first off this took me a couple of hours to do so no complaints about scalability, I do realize it won’t, but it’s a starting point!
First you’ll need the WSS 3.0 SDK
Once you’ve installed that, open up Visual Studio, create a new project and select the WebPart template from under C#->Sharepoint.
You’ll next need to create a DTO to store the post summary.
public class PostSummary
{
private string title;
private string summaryText;
private string postDateString;
private DateTime postDate;
private string author;
private string permalink;
private string sitelink;
public PostSummary( string title,
string author,
string summaryText,
DateTime postDate,
string sitelink,
string permalink)
{
...
}
}
This class also does some string manipulation to get the post time in a decent format and also overrides ToString() which we use to output the HTML we want to render for each post summary. It’s not important here, but is included in the source code.
Next we’ll look at the actual web part. This is basically a class which inherits from ‘WebPart’ and overrides it’s ‘Render’ method. We need to do 3 things in the render method.
- Loop over every site and identify those that use the blog template.
- Build a list of post summaries and sort it based on date, youngest first.
- Write our list out as HTML.
So
[Guid("4535f021-7e6e-46d4-b821-7a98007357ee")]
public class SiteWideRSSRiver : WebPart
{
protected override void Render(HtmlTextWriter writer)
{
List<PostSummary> postSummaryList = this.findPosts();
postSummaryList.Sort(new PostSummary.PostSummaryComparer());
this.WritePosts(writer, postSummaryList);
}
}
Ok, so now lets define those three bits.
Find Posts
We get the current Sharepoint site context and from that a collection of all the webs.
We iterate over that collection for each site, and then over that for each subsite and as we go we check if the title contains “Posts” (there’s probably a better way of determining what the template is but I couldn’t find it).
Once we have a blog templated site we get the latest post and work out the permalink and the site url and pass that into a new PostSummary along with the title, author, body text and publish date and add the new PostSummary to a list.
private List<PostSummary> FindPosts()
{
SPSite mySite = SPContext.Current.Site;
SPWebCollection subSites = mySite.AllWebs;
List<PostSummary> postSummaryList = new List<PostSummary>();
for (int i = 0; i < subSites.Count; i++)
{
SPListCollection lists = subSites[i].Lists;
for (int j = 0; j < lists.Count; j++)
{
if (lists[j].Title.Contains("Posts"))
{
SPListItem spListItem = lists[j].Items[lists[j].Items.Count - 1];
string defaultViewUrl = ResolveClientUrl(lists[j].DefaultViewUrl);
string sitelink = defaultViewUrl.Replace(this.PostDefaultViewPath, string.Empty);
string permalink = defaultViewUrl.Replace("AllPosts.aspx", "Post.aspx?ID=")
+ spListItem["Permalink"];
postSummaryList.Add(new PostSummary(spListItem.Title,
(string)spListItem["Author"],
(string)spListItem["Body"],
(DateTime)spListItem["Published"],
sitelink,
permalink));
}
}
}
return postSummaryList;
}
Once we have the list of latest posts from across the Sharepoint Site we need to sort it.
Sort the list
I created a child class inside PostSummary called PostSummaryComparer which just does a DateTime.Compare on the postDate field of the PostSummary and multiplies it by -1. This way we get the youngest post at the top, oldest at bottom.
public class PostSummaryComparer : IComparer<PostSummary>
{
public int Compare(PostSummary x, PostSummary y)
{
return DateTime.Compare(x.postDate, y.postDate) * -1;
}
}
Render it
Then it’s just a case of rendering it all out using the HTML Writer. I’ve hard-coded the number of posts to display at 5, but you can easily make this a property of the WebPart
private void WritePosts(HtmlTextWriter writer, List<PostSummary> postSummaryList)
{
int postsToShow = 0;
if (postSummaryList.Count < 5)
{
postsToShow = postSummaryList.Count;
}
else
{
postsToShow = 5;
}
for (int i = 0; i < postsToShow; i++)
{
writer.Write(postSummaryList[i].ToString());
}
}
And that’s all; I admit it’s a bit nasty but you get the gist!