This is the second part of a 2-part set of blog posts where we
describe a possible implementation for "single blog - multiple authors"
functionality:
- Part 1 - Admin view: enable author
maintenance on the blog post level;
- Part 2 - Public view: new
controls that allow filtering by
author of the blog post.
Part 2 - Public View: Controls that Allow Filtering by Post-level Author
All files and source code discussed in this post are available for
download.
We'll create two controls that allow post filtering by the author of the blog post maintained as described in Part 1:
- Blog Posts with Author Filter: custom control that enhances the built-in Blog Posts control by implementing an extra filter for the post author;
- Blog Authors: user control that lists contributors for selected blogs, and allows for post filtering by author.
2.1 Custom Control: Blog Posts with Author Filter
Functional description:
- Preserves all functionality implemented by the built-in BlogPosts control;
- Implements a new filter based on the blog post author. The author name is passed as a Query String parameter (named PostAuthor) when the user clicks on the Author link;
- When the new filter by author is applied, "Go Back" link is visible
Here are the steps required to implement the functional needs described above:
- Create a custom class "BlogPostsAuthorFilter.cs" that inherits from BlogPosts. We chose to create it in ~/App_Code folder rather than as an external library in order to avoid compile time dependencies and ensure compatibility with all Sitefinity versions 3.6, 3.7 (including future Service Packs for 3.7).
If your website is running in medium-trust - which is the case with most shared hosting plans (offered by DiscountASP, GoDaddy, etc.) - the custom control should be compiled as an external class library and deployed in the ~/bin folder in order to avoid security-related exceptions when the control is added to the toolbox:
namespace DataUniversal.Blogs
{
public class BlogPostsAuthorFilter : BlogPosts
{
public BlogPostsAuthorFilter()
{
}
}
}
- Override the following properties and methods
- Properties: ItemListTemplatePath, SingleItemTemplatePath - needed to provide the default templates. The external templates are available from Sitefinity, and have been included in the archive attached to this post (ContentViewItemList.ascx, ContentViewSingleItem.ascx)
public override string ItemListTemplatePath
{
get
{
object oPath = this.ViewState["ItemListTemplatePath"];
if (oPath != null)
return oPath.ToString();
return "~/Sitefinity/ControlTemplates/Blogs/ContentViewItemList.ascx";
}
set
{
this.ViewState["ItemListTemplatePath"] = value;
}
}
public override string SingleItemTemplatePath
{
get
{
object oPath = this.ViewState["SingleItemTemplatePath"];
if (oPath != null)
return oPath.ToString();
return "~/Sitefinity/ControlTemplates/Blogs/ContentViewSingleItem.ascx";
}
set
{
this.ViewState["SingleItemTemplatePath"] = value;
}
}
- Methods: CreateChildControls, SelectContentCount, SetItemMetadata - needed to apply the additional filter before creating the child controls, synchronize the content count used by the pager, and set the proper URL for the author link
protected override void CreateChildControls()
{
bool applyAuthorFilter = false;
if (Page != null && !String.IsNullOrEmpty(Page.Request.QueryString["PostAuthor"]))
{
string postAuthor = HttpUtility.UrlDecode(Page.Request.QueryString["PostAuthor"]);
ContentFilterBuilder filterBuilder = new ContentFilterBuilder(this);
filterBuilder.AddFilter(new MetaSearchInfo(MetaValueTypes.ShortText, "Author", postAuthor, SearchCondition.Equal, JoinType.And));
applyAuthorFilter = true;
}
base.CreateChildControls();
if (applyAuthorFilter)
{
ListContainer.BackLink.NavigateUrl = Page.Request.Url.AbsolutePath.ToLower();
ListContainer.BackLink.Visible = true;
}
}
protected override int SelectContentCount()
{
if (Page != null && !String.IsNullOrEmpty(Page.Request.QueryString["PostAuthor"]))
{
string postAuthor = HttpUtility.UrlDecode(this.Page.Request.QueryString["PostAuthor"]);
ContentFilterBuilder filterBuilder = this.GetFilterBuilder();
filterBuilder.AddFilter(new MetaSearchInfo(MetaValueTypes.ShortText, "Author", postAuthor, SearchCondition.Equal, JoinType.And));
int contentCount = Manager.GetContent(0, 0, SortExpression, filterBuilder.ParseTagFilter(), ContentStatus.Published, null, filterBuilder.ParseParentsFilter(), filterBuilder.ParseMetaFieldsFilter()).Count;
if (LimitListCount && contentCount > MaximumListCount)
contentCount = MaximumListCount;
return contentCount;
}
return base.SelectContentCount();
}
protected override void SetItemMetadata(Control itemContainer, IContent contentItem)
{
base.SetItemMetadata(itemContainer, contentItem);
HyperLink linkPostedBy = (HyperLink)FindContentViewControl("postedBy", itemContainer);
if (linkPostedBy != null)
{
object oMetaAuthor = contentItem.GetMetaData("Author");
string sMetaAuthor = String.Empty;
if (oMetaAuthor != null)
sMetaAuthor = oMetaAuthor.ToString();
string baseURL = String.Empty;
if (SingleContainer.BackLinks.Length > 0)
baseURL = SingleContainer.BackLinks[0].NavigateUrl;
if (String.IsNullOrEmpty(baseURL) && Page != null)
baseURL = Page.Request.Url.AbsolutePath.ToLower();
if (!String.IsNullOrEmpty(sMetaAuthor) && !String.IsNullOrEmpty(baseURL))
{
linkPostedBy.NavigateUrl = baseURL + "?PostAuthor=" + HttpUtility.UrlEncode(sMetaAuthor);
linkPostedBy.Text = sMetaAuthor;
}
}
}
- Register the new custom control in web.config in order to make it available in the toolbox:
<toolboxControls>
<clear />
...
<add name="Blog Posts with Author Filter" section="Data Universal" type="DataUniversal.Blogs.BlogPostsAuthorFilter,App_Code" />
...
The control can be seen in action on all blog pages on this website.
2.2 User Control: Blog Authors
Functional description:
- Displays a list of distinct post-level Author names, for each of the selected blogs; an author name is displayed as a link pointing to its parent blog page, and implements the query string parameter required for post filtering by author.
- One or more blogs can be selected from the list of available blogs; out of the selected blogs, only those with at least 1 post published in the past (compared to the current server date-time) will be included.
- The blog name visibility can be controlled, and whether to display it as a hyperlink pointing to the blog page.
- Visibility of the number of posts created by each author can be controlled. When visible, the number of posts is displayed after the author name, enclosed in parenthesis.
- The list of authors is sorted by (blog name, author name), in ascending order.
The user control is available (see ZIP archive attached to this post) in the following location: \UserControls\Data_Universal
- BlogAuthors.ascx
- BlogAuthors.ascx.cs
Upload the user control "BlogAuthors.ascx" using the built-in functionality available while in page edit mode; when prompted whether a code-behind file will be uploaded - choose 'yes' and point to the "BlogAuthors.ascx.cs" file.
Here's a screenshot of the control properties:

The control can be seen in action on all blog pages, right-hand sidebar.
All files and source code discussed in this post are available for
download.