More in this section
Blogs RSS feed

Adding Image to a Blog RSS Feed in Sitefinity

by Ivan D.Dimitrov

RSS feeds are a convenient way to inform users instantly when a new blog post is available for them to review and comment. This post will show you how to add an image in the feed’s list.

The first thing you will need to do is add a custom field to your blog posts. This field needs to be an image selector that persists the image URL as its value. I have used the resource available in Slavo Ingilizov’s blog. This selector persists the ID of the image in the form of a Guid, so in order for the image to be properly passed, we need to alter the Javascript so it persists the URL. The changes needed are in the SimpleImageSelector.js file, where you need to replace:

var imageUrl = args.get_dataItem().ThumbnailUrl;


var imageUrl = args.get_dataItem().MediaUrl;

And in the
SimpleImageSelectorDialog.js where you need to locate the _doneLinkClicked function and replace it with the one below:

_doneLinkClicked: function (sender, args) {      
        var selectedValue = this.get_imageSelector().get_selectedImageUrl();
        if (!selectedValue || selectedValue === "") {
            alert("No image selected.");
        else {


After that is done you can apply the custom field in the blog posts as per Slavo’s instructions.

After this is done we need to stream the image in the RSS. Sitefinity uses RSS 2.0. This means that all of the elements that are visible to the end user have to be part of the <channel> tag. Naturally streaming the custom field image with the default <image> xml tag will not work here as it is not a sub tag of the <channel> one. In order to be able to properly pass an image we need to do so with html so as to get freedom for sizing and styling. The only xml tag in the <channel> one that is able to display html is the <description> tag and it needs some modification in order to properly do so.

The first thing we need to do is to create a custom RSS outbound pipe. This way we can extend the default properties of Sitefinity’s default pipe. You need to create a class that inherits from our inbuilt RssOutboundPipe class. The code below presents a pipe with the name customRssOutboundPipe:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.ServiceModel.Syndication;
using System.Xml;
using System.Xml.Linq;
using Telerik.Sitefinity.Data.Summary;
using Telerik.Sitefinity.Modules.GenericContent;
using Telerik.Sitefinity.Modules.Libraries;
using Telerik.Sitefinity.Publishing;
using Telerik.Sitefinity.Publishing.Model;
using Telerik.Sitefinity.Publishing.Pipes;
using Telerik.Sitefinity.Publishing.Translators;
using Telerik.Sitefinity.Web.Utilities;
namespace SitefinityWebApp.RssOutboundPipe
    // specifies the pipe designer in the backend
    [PipeDesigner(null, typeof(CustomRssAtomPipeDesignerView))]
    public class CustomRssOutboundPipe : RSSOutboundPipe
        public override string Name
                return CustomRssOutboundPipe.PipeName;
        /// <summary>
        /// Creates a SyndicationItem object from the given data.
        /// </summary>
        /// <param name="values">The data used to build a SyndicationItem object.</param>
        /// <returns>A SyndicationItem object.</returns>
        protected override SyndicationItem BuildSyndicationItem(WrapperObject values)
            SyndicationItem item = new SyndicationItem();
            var properties = TypeDescriptor.GetProperties(values);
            var title = this.GetPropertyValue(values, properties, PublishingConstants.FieldTitle);
            title = PublishingHelper.SanitizeStringForXml(title);
            item.Title = new TextSyndicationContent(title);
            if (this.RssPipeSettings.OutputSettings != RssContentOutputSetting.TitleOnly)
                var content = this.GetPropertyValue(values, properties, PublishingConstants.FieldContent);
                //Resolve to real urls links and media(images, video, docs) pointing to internal sitefinity content by ID
                content = LinkParser.ResolveLinks(content, DynamicLinksParser.GetContentUrl, null, false, true);
                if (this.RssPipeSettings.OutputSettings == RssContentOutputSetting.TitleAndTruncatedContent)
                    content = SummaryParser.GetSummary(content, new SummarySettings(SummaryMode.None, -1, true));
                    if (content.Length > this.RssPipeSettings.ContentSize)
                        if (this.RssPipeSettings.ContentSize == 0)
                            content = String.Empty;
                            content = content.Substring(0, this.RssPipeSettings.ContentSize);
                            content += "...";
                content = PublishingHelper.SanitizeStringForXml(content);
            //BACK LINK to the web page with the original posting
            if (properties.Find(PublishingConstants.FieldLink, true) != null)
                var itemUrl = GetItemUrl(values);
                if (!string.IsNullOrEmpty(itemUrl))
                    item.Links.Add(SyndicationLink.CreateAlternateLink(new Uri(itemUrl)));
             var ownerFirstNameProp = properties.Find(PublishingConstants.FieldOwnerFirstName, true);
             var ownerLastNameProp = properties.Find(PublishingConstants.FieldOwnerLastName, true);
             var ownerEmailProp = properties.Find(PublishingConstants.FieldOwnerEmail, true);
             if (ownerFirstNameProp != null && ownerLastNameProp != null && ownerEmailProp != null)
                 item.Authors.Add(new SyndicationPerson(
                     (string)ownerFirstNameProp.GetValue(values) + " " +
            //PUBLICATION DATE
            var pubDateProp = properties.Find(PublishingConstants.FieldPublicationDate, true);
            if (pubDateProp != null)
                var pubDateVal = pubDateProp.GetValue(values);
                if (pubDateVal != null)
                    item.PublishDate = new DateTimeOffset(((DateTime)pubDateVal).ToUniversalTime());
            //ORIGINAL ITEM ID
            var itemIdProp = properties.Find(PublishingConstants.FieldItemId, true);
            if (itemIdProp != null)
                var itemIdVal = itemIdProp.GetValue(values);
                if (itemIdVal != null)
                    item.Id = String.Format("urn:uuid:{0}", itemIdVal.ToString());
            var catProp = properties.Find(PublishingConstants.FieldCategories, true);
            if (catProp != null)
                var catVal = catProp.GetValue(values);
                if (catVal != null)
                    var categories = ((string)catVal).Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var cat in categories)
                        item.Categories.Add(new SyndicationCategory(cat));
            var summaryProp = properties.Find(PublishingConstants.FieldSummary, true);
            if (summaryProp != null)
                var summaryVal = summaryProp.GetValue(values);
                if (summaryVal != null && !summaryVal.ToString().IsNullOrEmpty())
                    var summary = summaryVal.ToString();
                    summary = PublishingHelper.SanitizeStringForXml(summary);
                    item.Summary = new TextSyndicationContent(summary);
            return item;
        // registers the pipe
        public static void AddCustomRssOutboundPipe()
            // registers the pipe type
            PublishingSystemFactory.RegisterPipe(CustomRssOutboundPipe.PipeName, typeof(CustomRssOutboundPipe));
            // registers the pipe settings of the pipe
            var pipeSettings = RSSOutboundPipe.GetTemplatePipeSettings();
            pipeSettings.UIName = "Custom RSS feed";
            pipeSettings.PipeName = CustomRssOutboundPipe.PipeName;
            PublishingSystemFactory.RegisterTemplatePipeSettings(CustomRssOutboundPipe.PipeName, pipeSettings);
            PublishingSystemFactory.RegisterPipeSettings(CustomRssOutboundPipe.PipeName, pipeSettings);
            // registers the mappings for the pipe
            var mappingsList = RSSOutboundPipe.GetDefaultMappings();
            PublishingSystemFactory.RegisterPipeMappings(CustomRssOutboundPipe.PipeName, false, mappingsList);
            // registers the definitions for the pipe
            var definitions = PublishingSystemFactory.CreateDefaultRSSPipeDefinitions();
            PublishingSystemFactory.RegisterPipeDefinitions(CustomRssOutboundPipe.PipeName, definitions);
        private static void AddFieldNames(List<Mapping> mappingsList)
            foreach (var fieldName in CustomRssOutboundPipe.FieldNames)
                mappingsList.Add(PublishingSystemFactory.CreateMapping(fieldName, TransparentTranslator.TranslatorName, true, fieldName));
        // list all custom fields of your custom type
        private static readonly string[] FieldNames = new[] { "Image" };
        public const string PipeName = "CustomRssOutboundPipe";


We also need a designer for the pipe so it can be visible in the dialog placed under Administration->Alternative publishing:

namespace SitefinityWebApp.RssOutboundPipe
    public class CustomRssAtomPipeDesignerView : RssAtomPipeDesignerView
        public override IEnumerable<System.Web.UI.ScriptDescriptor> GetScriptDescriptors()
            // gets the base script descriptor
            var scriptDescriptor = (ScriptControlDescriptor)base.GetScriptDescriptors().Last();
            // replaces the component type in order not to inherit the js component
            scriptDescriptor.Type = typeof(RssAtomPipeDesignerView).FullName;
            // replaces the default pipe settings with the ones of the custom rss outbound pipe
            var settings = new Dictionary<string, object>();
            var defaults = PublishingSystemFactory.GetPipe(CustomRssOutboundPipe.PipeName).GetDefaultSettings();
            settings.Add("settings", defaults);
            settings.Add("pipe", new WcfPipeSettings(CustomRssOutboundPipe.PipeName, PublishingManager.GetProviderNameFromQueryString()));
            scriptDescriptor.AddProperty("_settingsData", settings);
            return new[] { scriptDescriptor };

The pipe needs to be registered in your Global asax as well:

protected void Application_Start(object sender, EventArgs e)
            Telerik.Sitefinity.Abstractions.Bootstrapper.Initialized += new EventHandler<Telerik.Sitefinity.Data.ExecutedEventArgs>(Bootstrapper_Initialized);
        void Bootstrapper_Initialized(object sender, ExecutedEventArgs e)
            if (e.CommandName == "Bootstrapped")


After you have created and registered your custom pipe, it is time to extend it so as it can pass the image from the custom field. As you can see, Sitefinity’s RssOutboundPipe uses the Syndication Item (http://msdn.microsoft.com/en-us/library/system.servicemodel.syndication.syndicationitem(v=vs.110).aspx) with all of its properties in order to build the RSS. As you can see this class does not build the <description> tag so we need to add it. We use the SyndicationItem.Element extensions to do so. We do a query to match the name of the syndication item with the name of the post and then pass the value of the custom blog posts field to the feed. In order to display the image properly we need to embed it in html. This is done with a CDATA section that forces the xml to ignore the html contained in it:

BlogsManager blogMan = BlogsManager.GetManager();
                var blog = blogMan.GetBlogPosts().Where(b => b.Status == Telerik.Sitefinity.GenericContent.Model.ContentLifecycleStatus.Live).ToList();
                foreach (var oneblog in blog)
                    if (item.Title.Text == oneblog.Title)
                        var Field = oneblog.GetValue("RSSImg");
                        new XElement("description",
                        new XCData(@"<img src=""" + Field + @""""  +" />" + "</div>" + content + "</div>")));


As you can see I have named my custom field RSSImage. You can name yours as you like, but remember to pass it correctly in the GetValue extension method.

Steps to set the sample:

  1. Download the sample.
  2. Set it according to this video.


Leave a comment
  1. Gary Apr 19, 2014
    I see how the custom blog property is populated into the description element, but I don't see how this relates to the adding of the "Image" field to the outbound pipe via the call to the AddFieldNames method. I was expecting to see some code in BuildSyndicationItem that sets the "Image" field name from the custom blog property. Am I not understanding something? I'm trying to build on this example to retrieve the "StartDate" from events, and use it to filter the items in BuildSyndicationItems, but I'm not seeing the connection.
  2. Saad Aug 02, 2014

    I'm using SF 7.1.

    When implementing custom RSS inbound pipe, how can we set custom field values? Like I have Category, Tags, Yes / No, and Image field. 

  3. Web Team Sep 29, 2014
    Well, how do you use the custom pipe then?
  4. Brett May 25, 2015

    After implementing the code above my custom News RSS feed now has two 'description' elements. One with the standard summary text and one containing the image markup.

    How do I remove the default description element?

  5. sudhir May 29, 2015


    I have a new feed link of wordpress which consist of images. When I use this feed to my website then it is only displaying content not images.

  6. josh Mar 24, 2016
    FYI as of SF 8.2 RssPipeSettings is no longer a property of RssOutboundPipe. They refactored it into a generic class and now you have to use PipeSettingsInternal. you might want to update your API change docs for this as it's not mentioned. thanks!
  7. Héctor Sustaita Jun 01, 2017

    When creating a Custom Outbound pipe for add a custom field to the RSS, the search index page in the backend throws the following message when clicking an existing index to edit it:

    "There are no settings suitable for this pipe type."

    The RSS works fine, but now I can't create or edit a search index.

    Anyone with this issue?

    Leave a comment