Twitter Integration with Sitefinity

Twitter has become a remarkable tool for building your community. Whether this means promoting your products and service, or mobilizing your followers to action, this has made it an ideal solution that cannot be ignored from freelancers to non-profits to enterprises. Who would have thought 140 characters can do so much?! Perhaps the short attention span attributed to fast pacing world may have contributed to the phenomenon.

Having a website is not enough anymore. You must have a blog, news, and even events to keep your visitors coming back for more. So how do you keep up with adding a Twitter to the mix? Well, hitting two birds with one stone of course (please don't throw real stones at real birds)! I am going to show how you can merge your existing processes of posting blogs, news, and events with automatically posting to Twitter! For this demonstration, I am going to use Sitefinity, but you can really apply these concepts to any content management system. Also, we will be using the Bit.ly service to shorten URL's to make better use of the 140 character limit on Twitter.

Let us start with the events module. First I must add extra profile fields to store the user's credentials for Twitter. I added these fields on the user level instead of the application level to give the flexibility of user's posting onto their own Twitter account. To add these fields to the user profile, I add the necessary fields to the web.config:

<profile defaultprovider="Sitefinity">
  <providers>
    <clear/>
    <add name="Sitefinity" connectionStringName="DefaultConnection" applicationName="/" type="Telerik.DataAccess.AspnetProviders.TelerikProfileProvider, Telerik.DataAccess"/>
  </providers>
  <properties>
    <add name="FirstName"/>
    <add name="LastName"/>
    <add name="Position"/>
    <add name="Nickname"/>
    <add name="Photo_Hidden"/>
    <add name="Photo" defaultValue="~/Sitefinity/Common/Images/defaultavatar.gif"/>
    <group name="InstantMessenger">
      <add name="IM_Type"/>
      <add name="IM_Value"/>
    </group>
    <group name="Phone">
      <add name="Value"/>
      <add name="Type"/>
    </group>
    <group name="Bitly">
      <add name="Login"/>
      <add name="Key"/>
    </group>
    <group name="Twitter">
        <add name="Username"/>
        <add name="Password"/>
    </group>
  </properties>
</profile>


Next thing we are going to do is add these profile fields to the user management screens. There are 2 files to do this in:

  1. ~/Sitefinity/Admin/CmsAdmin/MyProfile.aspx within the <cc1:ManageProfile ID="manageProfile"> tag
    <h3> API </h3>
    <fieldset class="userinfo set">
        <ol class="setIn">
            <li>
                <cc2:FieldLabel ID="lblBitly_Login" runat="server" Text="Bit.ly Login" TargetID="Bitly_Login">
                </cc2:FieldLabel>
                <asp:TextBox ID="Bitly_Login" runat="server"></asp:TextBox>
            </li>
            <li>
                <cc2:FieldLabel ID="lblBitly_Key" runat="server" Text="Bit.ly Key" TargetID="Bitly_Key">
                </cc2:FieldLabel>
                <asp:TextBox ID="Bitly_Key" runat="server"></asp:TextBox>
            </li>
            <li>
                <cc2:FieldLabel ID="lblTwitter_Username" runat="server" Text="Twitter Username" TargetID="Twitter_Username">
                </cc2:FieldLabel>
                <asp:TextBox ID="Twitter_Username" runat="server"></asp:TextBox>
            </li>
            <li>
                <cc2:FieldLabel ID="lblTwitter_Password" runat="server" Text="Twitter Password" TargetID="Twitter_Password">
                </cc2:FieldLabel>
                <asp:TextBox ID="Twitter_Password" runat="server" TextMode="Password"></asp:TextBox>
            </li>
        </ol>
    </fieldset>
    <div class="bottom">
        <div>
            <!-- -->
        </div>
    </div>
    


  2. In ~/Sitefinity/Admin/CmsAdmin/Users.aspx add the same code above in two places:
    • <cc1:manageprofile id="manageProfile"><InsertTemplate>
    • <cc1:manageprofile id="manageProfile"><EditTemplate>

This is all you need to do in Sitefinity to wire up the new user profile fields to the management screens. Fortunately, Sitefinity takes care of all the plumbing of persisting the data.

Now we will need some extra meta fields for the module items to store some status on the Twitter post. We do this by adding the meta fields in the web.config:

<cmsEngine defaultProvider="Generic_Content">
  <metaFields>
    <add key="Events.TwitterPost" valueType="Boolean" visible="True" searchable="False" sortable="False" defaultValue=""/>
    <add key="Events.TwitterPostDate" valueType="DateTime" visible="True" searchable="True" sortable="True" defaultValue=""/>
    <add key="Events.ShortUrl" valueType="ShortText" visible="True" searchable="True" sortable="True" defaultValue=""/>
  </metaFields>
</cmsEngine>


We must now adjust the control templates for the event management screens to give the user the option to posting to Twitter. There are two files that need some markup:

  1. In ~/Sitefinity/Admin/ControlTemplates/Events/EventsItemNew.ascx within the <sfgcn:contentmetafields id="MetaFields"> tag
    <h3>
        <asp:Literal ID="Literal16" runat="server" Text="<%$Resources:AdditionalInfo %>" /></h3>
    <fieldset class="set">
        <div class="setIn">
            <ol>
                <li>
                    <asp:Label ID="Label6" runat="server" Text='<%$Resources:TwitterPost %>' AssociatedControlID="TwitterPost"></asp:Label>
                    <asp:CheckBox ID="TwitterPost" runat="server"></asp:CheckBox>
                    <p class="example">
                        <asp:Literal ID="Literal18" runat="server" Text="<%$Resources:TwitterPostNote %>" />
                        <%$Resources:LastPosted %>: <asp:Literal ID="TwitterPostDate" runat="server"></asp:Literal></p>
                </li>
                <li>
                    <asp:Label ID="Label14" runat="server" Text='<%$Resources:TwitterHash %>' AssociatedControlID="TwitterHash"></asp:Label>
                    <asp:TextBox ID="TwitterHash" runat="server"></asp:TextBox>
                    <p class="example">
                        <asp:Literal ID="Literal30" runat="server" Text="<%$Resources:TwitterHashNote %>" /></p>
                </li>
                <li>
                    <asp:Label ID="Label13" runat="server" Text='<%$Resources:ShortUrl %>' AssociatedControlID="ShortUrl"></asp:Label>
                    <asp:TextBox ID="ShortUrl" runat="server"></asp:TextBox>
                    <p class="example">
                        <asp:Literal ID="Literal29" runat="server" Text="<%$Resources:ShortUrlNote %>" /></p>
                </li>
            </ol>
        </div>
    </fieldset>
    <div class="bottom">
        <div>
        </div>
    </div>
    


At this point, we have taken care of the interface. Here's what the screens should look like after your added these modifications:

User profile interface for updating the Twitter and Bit.ly credentials


Interface for creating items within a module. Also added here is the placeholder for a time the Twitter status was posted and hash tags that can be used for for the Twitter status for easy searching.

Now we are ready to get into some real code! We will extend the EventsItemEdit class by inheriting it. We will override the SaveContent() method to inject some code in there before it saves. What we will be doing is checking for the "Post to Twitter" flag to do the logic needed for updating Twitter.

We will be using the Yedda Twitter Library for the actual communication to Twitter and the Bit.ly API in C# for shortening URL's.

Here is the code that is overriden for EventsItemEdit.SaveContent():

public class EventsItemEdit : Telerik.Events.WebControls.Admin.EventsItemEdit
{
    private const string DEFAULT_EVENT_PAGE = "~/Events/View.aspx";

protected override void InitializeControls(System.Web.UI.Control viewContainer)
{
    //HANDLE PROCESSES ON EVENTS THAT INCLUDE NEWLY CREATED ITEMS.
    //THIS IS NEEDED SO WE HAVE AN ID IN DB FOR THESE PROCESSES SINCE THE SAVECONTENT 
    //OVERRIDE EXISTS/REDIRECTS BEFORE BEING ABLE TO SEND BACK THE CREATED OBJECT
    EventsManager.Executed += new EventHandler<Telerik.ExecutedEventArgs>(EventsPostSave_Executed);
}

public void EventsPostSave_Executed(object sender, Telerik.ExecutedEventArgs e)
{
    if (e.CommandName == "CreateContent" || e.CommandName == "UpdateContent")
    {
        IContent content = ContentManager.Providers[EventsManager.DefaultContentProvider].GetContent(e.ItemID);
        if (content != null)
        {
            //BUILD ITEM URL TO SEND TO EXTERNAL SERVICES
            string eventUrl = Utility.ResolveItemUrl(DEFAULT_EVENT_PAGE, content.UrlWithExtension, true);
            string shortUrl = this.BitlyHandler(content, eventUrl);
            this.TwitterHandler(content, shortUrl);
        }
    }
}

protected string BitlyHandler(IContent content, string url)
{
    if (!String.IsNullOrEmpty((string)content.GetMetaData("ShortUrl")))
    {
        //SHORT URL WAS DONE BEFORE
        return (string)content.GetMetaData("ShortUrl");
    }
    else
    {
        //CALL SHORTEN URL SERVICE
        url = Utility.ShortenUrl(url);
        content.SetMetaData("ShortUrl", url);
        EventsManager.Providers[EventsManager.DefaultContentProvider].SaveContent(content, false);
        return url;
    }
}

protected void TwitterHandler(IContent content, string url)
{
    //POST TO TWITTER IF APPLICABLE
    if (Convert.ToBoolean(content.GetMetaData("TwitterPost")))
    {
        if (Utility.UpdateTwitterStatus((string)content.GetMetaData("Title"), url, (string)content.GetMetaData("TwitterHash")))
        {
            //RESET FLAG IN CASE USER WOULD LIKE TO REPOST LATER
            content.SetMetaData("TwitterPost", false);
            //RECORD DATE OF TWITTER POST
            content.SetMetaData("TwitterPostDate", DateTime.Now);
            EventsManager.Providers[EventsManager.DefaultContentProvider].SaveContent(content, false);
        }
    }
}
}

This is the static methods used for the Twitter communication:

public static bool UpdateTwitterStatus(string content, string url, string hash)
{
    return UpdateTwitterStatus(content, url, hash, false);
}

public static bool UpdateTwitterStatus(string content, string url, string hash, bool makeShortUrl)
{
    //VALIDATE INPUT
    if (String.IsNullOrEmpty(content))
        return false;

    HttpContext context = HttpContext.Current;
    //CANNOT USE ProfileCommon SINCE WE ARE IN A SEPARATE LIBRARY FROM THE WEB APPLICATION
    string login = (string)context.Profile.GetPropertyValue("Twitter.Username");
    string password = (string)context.Profile.GetPropertyValue("Twitter.Password");
    bool success = false;

    if (!String.IsNullOrEmpty(login) && !String.IsNullOrEmpty(password))
    {
        //SHORTEN URL IF APPLICABLE
        if (makeShortUrl)
        {
            url = ShortenUrl(url);
        }

        //FORMAT INPUTS
        url = (!String.IsNullOrEmpty(url)) ? " " + url : String.Empty;
        hash = (!String.IsNullOrEmpty(hash)) ? " " + hash : String.Empty;

        //BUILD STRING ACCORDING TO TWITTER CHARACTER LIMIT
        string trailer = url + hash;
        int charsLeft = 140 - trailer.Length;
        if (content.Length > charsLeft)
        {
            content = content.Substring(0, charsLeft) + trailer;
        }
        {
            content += trailer;
        }

        //SEND POST TO TWITTER
        ServicePointManager.Expect100Continue = false;
        Twitter twit = new Twitter();
        try
        {
            twit.Update(login, password, content, Twitter.OutputFormatType.JSON);
            success = true;
        }
        catch (Exception ex)
        {
            //DO LOGGING HERE
        }
    }
    return success;
}

This is the static method used to shorten the URL:

public static string ShortenUrl(string url)
{
    //VALIDATE INPUT
    if (String.IsNullOrEmpty(url))
        return String.Empty;

    HttpContext context = HttpContext.Current;
    //CANNOT USE ProfileCommon SINCE WE ARE IN A SEPARATE LIBRARY FROM THE WEB APPLICATION
    string login = (string)context.Profile.GetPropertyValue("Bitly.Login");
    string apiKey = (string)context.Profile.GetPropertyValue("Bitly.Key");
    string shortenedUrl = String.Empty;

    if (!String.IsNullOrEmpty(login) && !String.IsNullOrEmpty(apiKey))
    {
        try
        {
            //ATTEMPT TO SHORTEN URL VIA BITLY SERVICE
            shortenedUrl = API.Bit(login, apiKey, url, "Shorten");
        }
        catch (Exception ex)
        {
            //DO LOGGING HERE
        }
    }
    return shortenedUrl;
}

This is the helper method to help resolve the content URL:

public static string ResolveItemUrl(string singleItemPage, string itemUrlWithExtension, bool resolveAsAbsoluteUrl)
{
    Page page = HttpContext.Current.Handler as Page;
    if (page != null)
    {
        singleItemPage = page.ResolveUrl(singleItemPage ?? "~/").Replace(".aspx", String.Empty) + itemUrlWithExtension;
    }
    if (resolveAsAbsoluteUrl)
    {
        singleItemPage = "http://" + page.Request.ServerVariables["SERVER_NAME"] + singleItemPage;
    }
    return singleItemPage;
}

Upon saving the event, the URL for the event is retrieved then shortened. We pass this into the Twitter method to do the actual status updating.

Twitter status posted through the Sitefinity administration

So now every time you post an event from your Sitefinity administration page, it gets sent to Twitter at the same time! Talk about efficiency. Stay tuned until next where I show how to integrate your CMS with Facebook.

HAPPY CODING!!

FormBuilder Module

FormBuilder is a module-based plugin that allows non-technical administrators to create unlimited forms from their control panel. What really sets this apart from other form builders is the ability to record form submissions into the database. I was able to leverage Sitefinity's clean API by extending the Generic Content module (for storing forms) and the Comments framework (for recording submissions).

While one of the most demanded feature for Sitefinity CMS is the ability for administrators to create forms on-the-fly, there is still no built-in capability of this with the current release (v3.7). Indeed, Sitefinity goes a long way to build a solid foundation to extend functionality, so I took it upon myself to create this feature and share it with the community. Thanks to Steven Webb for the inspiration!

FormBuilder is FREE to use and distribute as you wish. If you enjoy my work, please consider making a donation to help me expand on features and optimizations.


Features:

  • Ability for administrators to add input fields without writing a single line of code:
    1. Fieldset Group
    2. Text Input
    3. Text Area
    4. WYSIWYG Editor
    5. Date Input
    6. Number Input
    7. Label Text
    8. Check Box
    9. Check Box List
    10. Radio Button List
    11. Drop Down List
    12. Captcha Control
    13. Upload Input
    14. Hidden Field
  • Relevant options for each of the input fields above, such as validations, default values, read only, orientation, and much more
  • Add a comma separated list of emails for the "To", "From", "CC", and "BCC" fields
  • Define custom labels for the subject, send button, success message, failure message, validation message, and confirmation message
  • Ability to automatically email a confirmation message to the user who submitted the form
  • Standardized form generation allowing you to style using your own CSS
  • Define the number of columns for each fieldset section
  • Ability to record all form submissions for easy viewing in the admin control panel

Screenshots:

FormBuilder: Create a Form

Interface for creating a form within the admin control panel


FormBuilder: Add to Page

Drag-and-Drop Control to Page with Form Selector


FormBuilder: Frontend

Frontend interface of form for user to submit


FormBuilder: Tracking

Track form submissions from admin control panel


FormBuilder: Tracking Details

Detailed view of submission including response and meta info.



Running Environment:

The form builder has been fully tested on

  • Sitefinity 3.7 SP2
  • ASP.NET 3.5
  • IIS7

Note: If enough people request previous versions (and perhaps kick a donation or two- see sidebar), I'll gladly compile and upload them.


Download FormBuilder:

Download FormBuilder


Installation:

  1. Copy the contents of the "Website" folder to your Sitefinity folder.
  2. Merge the App.config configurations into your Sitefinity Web.config.
  3. Add ~/Sitefinity/Admin/ControlTemplates/Common/Custom/ButtonSelector.ascx
  4. Add ~/Sitefinity/Common/ToolsFile.xml
  5. That's it!


Source Code:

Download FormBuilder Source

To keep the community contributions coming:

  • Provide your feedback
  • Make a donation

Updated Version of FormBuilder Includes:

  • Allow admin to enter form code from control panel (instead of just thru database)
  • Allow copying of forms
  • Highlight field row in FormBuilder so it can be easier to see which row you are editing/deleting
  • Added option for not sending hidden input in email
  • Added column span for FormBuilder fields
  • Allow to specify library for FormBuilder upload field
  • Added upload control for FormBuilder
  • Exports of submissions are in CSV format
  • Added rich text control for FormBuilder
  • Set on focus for the validator instead of scrolling to top
  • Option to prefill form based on submitted sender in URL id
  • Option to clear form after submit
  • Allow to use a send image button for FormBuilder
  • Allow to add numeric input from FormBuilder with number options
  • Allow disable email option by not specifying "to" address
  • Add tooltip option for input instructions
  • Allow current date option for date input by using #now keyword
  • Allow to specify text and value for drop down, radio button list, and checkbox list
  • Allow form to redirect to page
  • Allow hidden inputs to be added to form
  • Remove default checkmark for checkbox and radiobutton list input
  • Make label field unlimited length for all inputs
  • other minor bug fixes and optimizations

You can help development and support continue by chipping in :)

ENJOY!!

News Rotator Plugin

News Rotator is a plugin that displays news in a rotator fashion anywhere on your site. It slides through all the news you have available on your website and displays a nicely formatted thumbnail, title, and time of the it was published. A click of the slideshow will take you to the full news page. A great way to showcase your articles!

News Rotator is FREE to use and distribute as you wish. If you enjoy my work, please consider making a donation to help me expand on features and optimizations.


Features:

  • Drag-and-drop control that can be added to any page
  • Reads your news automatically without further configurations
  • Filter rotator by one or more categories
  • Display expired and/or upcoming news
  • Specify the news page to open when clicked
  • Choose to open event in a new or current window
  • Adjust slideshow animation and delay time
  • Choose from several built-in skins

Screenshots:

News Rotator

News rotator in action. Slides through the news one by one.


News Rotator: Control Designer

Control designer interface to adjust the rotator configurations



Running Environment:

The news rotator has been fully tested on

  • Sitefinity 3.7 SP2
  • ASP.NET 3.5
  • IIS7

Note: If enough people request previous versions (and perhaps kick a donation or two- see sidebar), I'll gladly compile and upload them.


Download News Rotator:

Download News Rotator for Sitefinity

Files in package are:

  • ~/bin/Netopia.Sitefinity.News.dll
  • ~/bin/Netopia.Sitefinity.GenericContent.dll
  • ~/bin/Netopia.Common.dll
  • ~/App.config
  • ~/readme.txt


Installation:

  1. Extract the bin folder files into your Sitefinity bin folder.
  2. Add the App.config configurations into your Sitefinity Web.config.
  3. That's it!


Source Code:

Download News Rotator Source

To keep the community contributions coming:

  • Provide your feedback
  • Make a donation

ENJOY!!

Events Rotator Plugin

Events Rotator is a plugin that displays events in a rotator fashion anywhere on your site. It slides through all the events you have available on your website and displays a nicely formatted thumbnail, title, and time of the event. A click of the slideshow will take you to the full event page. A great way to showcase your events!

Events Rotator is FREE to use and distribute as you wish. If you enjoy my work, please consider making a donation to help me expand on features and optimizations.


Features:

  • Drag-and-drop control that can be added to any page
  • Reads your events automatically without further configurations
  • Filter rotator by one or more categories
  • Display expired and/or upcoming events
  • Specify the event page to open when clicked
  • Choose to open event in a new or current window
  • Adjust slideshow animation and delay time
  • Choose from several built-in skins
  • New thumbnail selector for events

Screenshots:

Events Rotator

Events rotator in action. Slides through the events one by one.


Events Rotator: Control Designer

Control designer interface to adjust the rotator configurations


Events Rotator: Thumbnail Selector

Specify event thumbnail from library, relative path, or URL.



Running Environment:

The events rotator has been fully tested on

  • Sitefinity 3.7 SP2
  • ASP.NET 3.5
  • IIS7

Note: If enough people request previous versions (and perhaps kick a donation or two- see sidebar), I'll gladly compile and upload them.


Download Events Rotator:

Download Events Rotator for Sitefinity

Files in package are:

  • ~/App_Data/Configuration/Telerik.Sitefinity.Configuration.ControlsConfig.xml
  • ~/bin/Netopia.Sitefinity.Events.dll
  • ~/bin/Netopia.Sitefinity.GenericContent.dll
  • ~/bin/Netopia.Common.dll
  • ~/Sitefinity/Admin/ControlTemplates/Common/Custom/ButtonSelector.ascx
  • ~/Sitefinity/Admin/ControlTemplates/Common/Custom/App_LocalResources/ButtonSelector.ascx.resx
  • ~/Sitefinity/Admin/ControlTemplates/Events/EventsItemEdit.ascx
  • ~/Sitefinity/Admin/ControlTemplates/Events/EventsItemNew.ascx
  • ~/Sitefinity/Admin/ControlTemplates/Events/App_LocalResources/EventsItemEdit.ascx.resx
  • ~/Sitefinity/Admin/ControlTemplates/Events/App_LocalResources/EventsItemNew.ascx.resx
  • ~/Sitefinity/Admin/Themes/Default/Modules.css
  • ~/App.config
  • ~/readme.txt


Installation:

  1. Copy the structure of the App_Data, bin, and Sitefinity folders into your Sitefinity website. Use caution not to overwrite any of your own customizations.
  2. Add the App.config configurations into your Sitefinity Web.config.
  3. That's it!


Source Code:

Download Events Rotator Source

To keep the community contributions coming:

  • Provide your feedback
  • Make a donation

ENJOY!!

Events Map Plugin

Events Map is a plugin that displays events on a global map via Google Maps. It produces the map with pins of all the events you have available on your website. A click of the pin will open a billboard-type section on the map with the event details with a link to the event page. An excellent tool for international organizations to communicate events world-wide to their community.

Events Map is FREE to use and distribute as you wish. If you enjoy my work, please consider making a donation to help me expand on features and optimizations.


Features:

  • Drag-and-drop control that can be added to any page
  • Reads your events automatically without further configurations
  • Filter map by one or more categories
  • Display expired and/or upcoming events
  • Specify the event page to open when clicked
  • Choose to open event in a new or current window
  • Use your existing Google Maps API key defined in the Events module
  • Set Google API settings directly from the control designer without writing any code

Screenshots:

Events Map

Events pinned on the map around the world


Events Map

Events pinned on the map in satellite view


Events Map: Control Designer

Control Designer interface for setting configurations


Events Map: GMap Control Designer

Control Designer interface for setting Google API configurations



Running Environment:

The events map has been fully tested on

  • Sitefinity 3.7 SP2
  • ASP.NET 3.5
  • IIS7

Note: If enough people request previous versions (and perhaps kick a donation or two- see sidebar), I'll gladly compile and upload them.


Download Events Map:

Download Events Map for Sitefinity

Files in package are:

  • ~/bin/Netopia.Sitefinity.Events.dll
  • ~/bin/Netopia.Sitefinity.GenericContent.dll
  • ~/bin/Netopia.Common.dll
  • ~/bin/GMaps.dll
  • ~/App.config
  • ~/readme.txt


Installation:

  1. Extract the bin folder files into your Sitefinity bin folder.
  2. Add the App.config configurations into your Sitefinity Web.config.
  3. Add your Google Maps API key to the Geomapping settings of your Events module.
  4. That's it!


Source Code:

Download Events Map Source

To keep the community contributions coming:

  • Provide your feedback
  • Make a donation

ENJOY!!

Welcome!

Welcome to my blog where I put, from time to time, some posts regarding topics connected with programming (Asp.Net, C#, Javascript, e-Commerce, internet marketing, social networking), computers in general, and my projects. It would be based on what I am currently doing, what I have discovered, and what I have created. I hope you enjoy it. Please leave some comments if you find any post useful or interesting.
Subscribe to RSS Feed