Custom fields in RSS feed?

Topics: Customizing Orchard
Mar 27, 2014 at 3:01 PM
Edited Mar 27, 2014 at 7:14 PM
Hi all,

Newish to Orchard and trying to work out how to build out a RSS feed for my list of blogposts.

A little googling let me know that a projection module automatically exposes a feed, and I've managed that much. However the auto created feed doesn't include any of the related media items. I'm trying to get my feed to serve up both the blog post summaries and the associated images.

Anyone have some guidance for me?

EDIT: For clarity, I have a content type that has blogpost as a part along with several fields including a DefaultImage. I'd like the RSS to serve up Defaultimage.uri along with the standard bits.
Mar 27, 2014 at 6:17 PM
Or, a more general question, how do you programatically access Fields on a ContentItem?

With some digging I've found where the RSS feed is built. Based on that I can roughly see where I would make chanes, but can't figure out how you would access the dynamic fields that are defined on a ContentItem.
Mar 28, 2014 at 6:12 PM
Edited Mar 28, 2014 at 6:14 PM
For any that get stuck on the same problem, I was able to solve it.

First, here's a good general article on building out a feed in a custom module.

Second, my actual solution was to piggyback on the existing Feed stuff in the Projection module. I added the QueryFeedItemBuilder shown below to the Projection module. It's a little hacky in that I'm using string matching on field names to determine how I access their dynamic elements, but it works. If someone has an idea for a cleaner version that automatically unpacks the dynamic elements I'd be all ears.
namespace Orchard.Projections.StandardQueries
    public class QueryFeedItemBuilder : IFeedItemBuilder
        private readonly IContentManager _contentManager;

        public QueryFeedItemBuilder(
            IContentManager contentManager)
            _contentManager = contentManager;
            T = NullLocalizer.Instance;

        public Localizer T { get; set; }

        public void Populate(FeedContext context)
                c =>
                        foreach (var feedItem in context.Response.Items.OfType<FeedItem<ContentItem>>())
                            var contentItem = feedItem.Item;
                                foreach (var part in contentItem.Parts)
                                    // extract data you're interested in from parts
                                    foreach (var field in part.Fields)
                                        dynamic theField = field;
                                        // extract data you're interested in from fields
                                        if (field.Name == "IntroductoryText")
                                            feedItem.Element.SetElementValue(field.Name, theField.Value);
                                        if (field.Name == "DefaultImage")
                                            feedItem.Element.SetElementValue(field.Name, theField.Url);
                                        if (field.Name == "ArticleDate")
                                            feedItem.Element.SetElementValue(field.Name, theField.DateTime);
Marked as answer by owleabf on 3/28/2014 at 11:12 AM
Dec 7, 2014 at 5:40 PM
If you know the content types and field names that you are interested in, you can always cast the contentitem to a dynamic and then access things as named properties.

Good reference to the concept here:

Here's an example of accessing a custom field named 'BlogMedia' that has been added to the BlogPost content type:
foreach (var feedItem in context.Response.Items.OfType<FeedItem<ContentItem>>())
    if (feedItem.Item.ContentType == "BlogPost")
        //first get the default ContentPart for the content type
        dynamic blogPost = ((dynamic)feedItem.Item).BlogPost;

        //get BlogMedia field
        MediaLibraryPickerField mediaPicker = blogPost.BlogMedia;
In this example the key is knowing that there is a default ContentPart with the same name as the ContentType 'BlogPost'. This is the part that the fields are actually added to. In other scenarios fields may reside on a different part, but the same idea still applies:
dynamic somePart = ((dynamic)feedItem.Item).SomePart;
var field = somePart.SomeField;
Casting content items or content parts to dynamic is your friend for gaining access to things by name.