World is now on Opti ID! Learn more

Magnus Rahl
May 4, 2011
  5035
(0 votes)

Creating feeds in Clubs and for external events

This post actually explains two ideas: Feeds for clubs and (feed) stories for objects external to the EPiServer Community platform.

Aggregating a feed for a Club

The EPiServer Community NewsFeed system is, in it’s vanilla form, very user-centric. Either you aggregate feeds for a particular user (the minifeed) or for a user’s friends (the newsfeed).

A quick recap of the NewsFeed system:

  • The newsfeed aggregates Stories.
  • You as a developer decide how Stories are created when something “happens” in your site, they aren’t auto-generated.
  • A Story stores tuplets of the type actor – action – target, or: someone (“User A”) performed some action on (“commented on”) something (“user B’s blog post”).
  • Stories can have multiple actors and multiple targets. The actors are IAuthors (generally a UserAuthor) and the Targets are Community entities.
  • Stories can have Attachments (actually the are attached to the actor) that are other entities.

 

The key to (more easily) creating a news feed for something other than a user (the actor) is the NewsFeedHandler.GetNewsFeedStoriesByTarget method. As the method name indicates it aggregates stories by their target rather than the actor as is the case when building mini- and newsfeeds. This can be used to create a feed in a Club which for example shows the stories created when users join the Club, because those stories should generally include the Club in it’s targets. “User A joined this club”, could be an interesting piece of information, but what if you want more…

In Wonderland: Targets as “actors”

In a current project the Clubs are not created by site users or moderators which is common, but are created in code to reflect “departments”. So the Clubs could be seen as profiles for the departments just like the user profiles (MyPages).

Without going in to details, the Clubs can even act on their own, which should make them actors in Stories, right? But instead we use the target feed to get those stories. As actor we simply use the Club’s Author (which is a system user since the Clubs are created by the system but have to have an author) and the Club is still the target. But then we stuff whatever is the “real” target of the action in the StoryAttachments:

// Get some club to create a story for
Club club = GetClub();
// Get some entity to attach and some action used for this entity
IEntity realTarget = GetRealTarget();
string action = "MyAction";
// Create attachments to the story
var storyAttachments = new EntityCollection();
storyAttachments.Add(realTarget);
// Use the club's Author as actor
var author = AuthorHandler.Instance.ChangeAuthor(null, club.Author);
// Create the story with attachment
var story = new NewsFeedStory(
    new NewsFeedAction(action, NewsFeedActionCapability.MultipleTargets
                                | NewsFeedActionCapability.MultipleActors),
    author, storyAttachments, club);
// Persist the story to database
NewsFeedHandler.Instance.AddStory(story);

Then we can pull out a feed for the Club using GetNewsFeedStoriesByTarget and render stuff like “Club A [target] posted [action] a new KPI [story attachment]”.

We can even mix these things in the users’ newsfeeds by getting the target feeds for Clubs in which they have memberships. That requires several calls and makes the paging features useless, but as the number of memberships is generally limited and the newsfeed only shows a few items without paging we accepted this performance penalty.

Creating stories for actions outside the Community

Since the departments also use other systems other actions that are of interest to the users can happen to “entities” outside the Community platform. In a deep integration scenario we would create custom Entity Providers for these external entities and either reflect the actual entities in the external systems or create mirror entities in the Community. However, we found that such a deep integration isn’t often needed.

Instead, since the other systems are also web-based we found it was enough to be able to link to the original content/entity in the external system. For this we need only one type of custom entity, and a simple one too. Say hello to the UrlEntity, which only has the string properties Url and Title and is stored in the DDS.

We currently use a scheduled job which polls the external systems for changes and creates stories for the appropriate Club and adds story attachments using the UrlEntity. The code is basically the same as I have already demonstrated, but imagine realTarget created by something like this:

// Pick up the external object to process and create a UrlEntity
var externalObject = GetExternalObjectFromContext();
IEntity realTarget = new UrlEntity(GetUrl(externalObject), GetTitle(externalObject));
realTarget = UrlEntityHandler.Instance.AddEntity(realTarget);

We could save just the URL and instead construct the title by calling the URL or some service related to it, but that would add external calls when rendering. By saving a descriptive text in the entity we add some data but skip external calls in rendering.

Source code

You can find the source code for the UrlEntity can be found in the code section. It is based on the DynamicDataStoreEntity which is distributed in the templates of the Relate 2 R2 package. I chose not to include the classes from there to avoid copyright hassles.

May 04, 2011

Comments

Please login to comment.
Latest blogs
Make Global Assets Site- and Language-Aware at Indexing Time

I had a support case the other day with a question around search on global assets on a multisite. This is the result of that investigation. This co...

dada | Jun 26, 2025

The remote server returned an error: (400) Bad Request – when configuring Azure Storage for an older Optimizely CMS site

How to fix a strange issue that occurred when I moved editor-uploaded files for some old Optimizely CMS 11 solutions to Azure Storage.

Tomas Hensrud Gulla | Jun 26, 2025 |

Enable Opal AI for your Optimizely products

Learn how to enable Opal AI, and meet your infinite workforce.

Tomas Hensrud Gulla | Jun 25, 2025 |

Deploying to Optimizely Frontend Hosting: A Practical Guide

Optimizely Frontend Hosting is a cloud-based solution for deploying headless frontend applications - currently supporting only Next.js projects. It...

Szymon Uryga | Jun 25, 2025

World on Opti ID

We're excited to announce that world.optimizely.com is now integrated with Opti ID! What does this mean for you? New Users:  You can now log in wit...

Patrick Lam | Jun 22, 2025

Avoid Scandinavian Letters in File Names in Optimizely CMS

Discover how Scandinavian letters in file names can break media in Optimizely CMS—and learn a simple code fix to automatically sanitize uploads for...

Henning Sjørbotten | Jun 19, 2025 |