A critical vulnerability was discovered in React Server Components (Next.js). Our systems remain protected but we advise to update packages to newest version. Learn More

Magnus Rahl
May 4, 2011
  5079
(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
A day in the life of an Optimizely OMVP: Learning Optimizely Just Got Easier: Introducing the Optimizely Learning Centre

On the back of my last post about the Opti Graph Learning Centre, I am now happy to announce a revamped interactive learning platform that makes...

Graham Carr | Jan 31, 2026

Scheduled job for deleting content types and all related content

In my previous blog post which was about getting an overview of your sites content https://world.optimizely.com/blogs/Per-Nergard/Dates/2026/1/sche...

Per Nergård (MVP) | Jan 30, 2026

Working With Applications in Optimizely CMS 13

💡 Note:  The following content has been written based on Optimizely CMS 13 Preview 2 and may not accurately reflect the final release version. As...

Mark Stott | Jan 30, 2026

Experimentation at Speed Using Optimizely Opal and Web Experimentation

If you are working in experimentation, you will know that speed matters. The quicker you can go from idea to implementation, the faster you can...

Minesh Shah (Netcel) | Jan 30, 2026