A new feature named Site Aggregation is available in the BlogEngine.NET developer builds, and will of course be available in the next public release. Site Aggregation is a feature related to Multiple Blog instances and this has been asked about by several people.
What is Site Aggregation?
You can designate up to 1 blog instance as being the Site Aggregation instance. Typically it would be the primary blog instance. When a blog instance becomes a Site Aggregation instance, the data displayed on the homepage, RSS feed and widgets contain blog posts from all the blog instances (see below for a complete list). So the data is an aggregate of the blog posts across all instances.
This is useful for site visitors who will be able to visit the main blog, and see blog posts across all instances. And if the RSS feed is subscribed to, that too aggregates blog posts across all instances.
The main homepage, Posts by Tag page, and Posts by Date Range pages display the site aggregate data. All the main widgets including the Tag Cloud, Recent Comments, Month List, Recent Posts, Calendar also take into account the site aggregate posts. The Search results page, and RSS feed too.
For each post listed, clicking on the post title will take you to that post within that post's blog instance. Each post usually also lists Tags and Categories tied to that post. Clicking on a tag or category link will take you to the tag/category listing page for that post's blog instance (i.e. you will leave the site aggregate blog).
What's Not Included
Category based pages/widgets do not currently aggregate posts across all sites. In particular, this includes the Category List widget and the Archive page. These items still can be used on the site aggregate blog instance, but they will only display Posts for the site aggregate blog instance -- not for any of the non-site aggregate blogs. The code needed to make these Category pages work with the site aggregated data is partially implemented in the Category core class (in particular, Category.AllBlogCategories and Category.ApplicableCategories), but some more work is needed for this. It may not be until the following release where these category widgets/pages are site-aggregate capable.
The other item which is not included are Pages. I think in most cases, it is preferable that Pages are not aggregated across all sites.
Configuring the Site Aggregate Blog Instance
It's very easy to designate a blog instance as being the site aggregate blog instance. On the Blogs management page, there is a new "Is For Site Aggregation" property/checkbox you can check -- as shown below.
A Look at the Site Aggregate Blog Instance
In my test system, I have a primary blog instance, which is also the site aggregate blog instance, and 2 sub-blogs. One sub-blog uses a virtual path, and the other sub-blog uses a different hostname. Each blog instance has a post in it. Here's what the homepage of the site aggregate blog instance looks like:
Similarly, here's a view of the RSS feed:
Site Aggregation Site - Includes "Local" Posts
The Site Aggregation site includes posts from other blog instances, as well as posts from its own instance (local posts). This means you can create posts in the site aggregation instance as well, which is probably a handy feature for some.
Relative & Absolute Links
One issue that is accounted for is if you are using different hostnames for your blog instances. For example, if your site aggregation instance is running at www.example.com and you have a sub-blog running at sub1.example.com, a lot of the links in BlogEngine.NET use relative paths, via RelativeLink and RelativeWebRoot. A typical example is a hyperlink that you would find in PostView.ascx.
<a href="<%=Post.RelativeLink %>" class="taggedlink"><%=Server.HtmlEncode(Post.Title) %></a>
This URL in the HREF would end up being an invalid URL when the site aggregation site is displaying a post for sub1.example.com. It would need to be an absolute link to "escape" out of the current hostname and get over to the other hostname (sub1.example.com). The simple solution is to convert all these RelativeLink to AbsoluteLink. A new property has been created off of IPublishable named RelativeOrAbsoluteLink. This will return a relative link if it works, and if not, it will return an absolute link. While an absolute link in theory always works, there are some advantages to using relative paths whenever possible. So when using this new RelativeOrAbsoluteLink property, if the sub-blog's hostname matches the hostname of the site aggregation blog instance, you'll get a relative link, otherwise an absolute link. Because the minority of BlogEngine.NET users won't be this situation where they are (a) using multiple blogs, (b) using the Site Aggregation feature, and (c) using different hostnames, RelativeOrAbsoluteLink will basically preserve backwards compatibility for everyone else not in this situation.
On this note, if you are using a custom theme, you may need to change RelativeLink in the PostView.ascx page to RelativeOrAbsoluteLink -- if you are in this situation.
A similar new property has been created in the Utils class, named RelativeOrAbsoluteWebRoot. Just like RelativeOrAbsoluteLink, RelativeOrAbsoluteWebRoot will return the RelativeWebRoot if it works, otherwise it will return AbsoluteWebRoot.
AllBlogPosts and ApplicableBlogPosts
These are 2 new properties in the Post class, which are used to support this site aggregation feature. AllBlogPosts is a list of posts across all blog instances. It's very similar to Post.Posts. Post.Posts is just for the current blog instance, where Post.AllBlogPosts is posts across all instances. The only real challenge here is the blog posts for a particular blog instance are not loaded into memory until the first time that blog instance is hit. If the site aggregation blog is hit before some of the sub-blogs have been hit, the data (Posts) for those sub-blogs will not yet be loaded in memory. The AllBlogPosts property takes care of this by loading the posts of these sub-blogs into memory that have not yet had their first hit.
ApplicableBlogPosts is a shortcut property that either returns AllBlogPosts or Posts depending on which one is needed.
The Category class has similar properties that have been added to it -- AllBlogCategories and ApplicableBlogCategories. These properties will be useful when the Archive page and Category based widgets such as the Category widget become site aggregate data capable (as mentioned above, these items are not yet site aggregate capable).
Blog and BlogId added to BusinessBase
The last notable change for this feature is the BusinessBase class now has Blog and BlogId properties. This means objects such as Post, Category, BlogRollItem (and anything else inheriting from BusinessBase) are now aware of which blog instance they belong to. This has a lot of potential uses. The main purpose for this at this point is properties such as RelativeLink (as in Post.RelativeLink) now take into account its blog instance's virtual path and hostname. So when working with Post.AllBlogPosts which contains blog posts across all the blog instances, calling Post.RelativeLink or Post.AbsoluteLink on any of the posts in this AllBlogPosts collection will return the correct path. As noted above, it's not safe to use Post.RelativeLink especially when working with Post.AllBlogPosts data. Instead, Post.RelativeOrAbsoluteLink or just Post.AbsoluteLink are the safer choices.
Give it a Try
If you think this new Site Aggregation feature may be of use to you, I encourage you to try it out, either now or once the beta for the next version of BlogEngine.NET comes out. The best place to bring up any issues or suggestions regarding this feature is in the CodePlex discussions group.