Creating Shortcodes for Sitefinity Blog Posts

Creating Shortcodes for Sitefinity Blog Posts

Posted on December 10, 2012 0 Comments

The content you're reading is getting on in years
This post is on the older side and its content may be out of date.
Be sure to visit our blogs homepage for our latest news, updates and information.

We previously looked at how you can use Sitefinity's support for External Widget Templates to add support for shortcodes in Sitefinity content by building a simple YouTube shortcode helper button.

In our last example today, we'll take things one step further and create a Sitefinity Blog Post shortcode helper. The idea is to allow users to easily link to any blog post in a content block (or other content item), complete with a user-friendly selector.

Setting the Blog Default Page

Before you begin, be sure that you have setup a default page for your blog, as described in step 5 of the documentation here: Creating A Blog.

Sitefinity-Blog-Default-Page

This is crucial, as it is this default page property we will use to generate the Url to the specific blog post later in this example.

Blog Post Selector Dialog

Next, we need to create a selector dialog to show the list of blog posts to be selected. This can be accomplished easily by adding a simple web form (aspx) that will be shown when the user clicks the Blog Post Shortcode button.

We can use any element to show the blog post list, such as a dropdown menu or radio button list, but because of the rich client-side API of the Telerik AJAX controls, which are of course, included with Sitefinity, we'll go ahead and use the RadListBox.

Add a new web form to your project, and add the following markup and script.

 <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server" />

        <h2>Select a blog post</h2>
        <telerik:RadListBox ID="BlogPostsList" runat="server" DataTextField="Title" DataValueField="Id" />
        <input type="button" onclick="selectAndClose()" value="Insert" />
        <input type="button" onclick="closeWindow()" value="Cancel" />
        

        <script type="text/javascript">

            // helper method to get the RadWindow container
            function getRadWindow() {
                if (window.radWindow) {
                    return window.radWindow;
                }

                if (window.frameElement && window.frameElement.radWindow) {
                    return window.frameElement.radWindow;
                }

                return null;
            }

            // fires when the Insert button is clicked
            function selectAndClose() 
            {
                // get the RadListBox
                var listbox = $find("<%= BlogPostsList.ClientID %>");

                // retrieve the selected item
                var item = listbox.get_selectedItem();

                // pass the selected Guid back to the widget via the close argument
                getRadWindow().close(item.get_value()); 
            }

            // fires when the Cancel button is clicked
            function closeWindow() {
                getRadWindow().close(null);
            }
        </script>

    </form>

The RadListBox is eventually going to be bound to a list of Blog Posts, and therefore has it's Text and Value properties set to bind to the Title and Id respectively. The script simply returns the selected value (the Blog Post Id) back to the calling Content Block widget so it can be pasted into the editor later in this post.

Next, in the code-behind, we simply use the Sitefinity API to bind the RadListBox to a list of Blog Posts. In this simple example, I'm just grabbing all the posts in the system on Page Load and binding them to the RadListBox.

 protected void Page_Load(object sender, EventArgs e)
    {
        using (var api = App.WorkWith())
        {
            var blogPosts = api.BlogPosts().Published().OrderBy(p => p.Title).Get();
            BlogPostsList.DataSource = blogPosts;
            BlogPostsList.DataBind();
        }
    }

A more real-world scenario might have additional controls to select from different blogs, or filter by author, but the basic principle is the same: the RadListBox will show a list of titles, which will then return the Id to the Content Block.

Sitefinity-Custom-Tool-Button-Insert-Blog-Post

Adding the Custom HtmlField RadEditor Toolbar Button

We already looked at how to add custom items to the RadEditor toolbar, so all we need to do now is define the behavior that will show our dialog, and insert the shortcode when selected.

Add the following script to the HtmlField template.

<script type="text/javascript">
    Telerik.Web.UI.Editor.CommandList["BlogPost"] = function (commandName, editor, args) {
        var myCallbackFunction = function (sender, args) {
            if (args == null) return;
            editor.pasteHtml(String.format("[blogpost:{0}]", args))
        }

        editor.showExternalDialog(
            '/Templates/BlogPostSelector.aspx',
            null,
            270,
            300,
            myCallbackFunction,
            null,
            'Insert Blog Post',
            true,
            Telerik.Web.UI.WindowBehaviors.Close + Telerik.Web.UI.WindowBehaviors.Move,
            false,
            false);
    };
</script>

Calling editor.ShowExternalDialog is all we need to do to show our custom page in the built-in RadWindow for the editor. For specific details about the arguments of this method, be sure to see the full documentation: Add Custom Dialogs.

The key argument is the first Url parameter, which identifies the path to our custom web form, and the fifth callback parameter, which points to a callback function that should execute when the dialog closes.

This method is defined above, and simply takes the argument (which as explained previously, contains the blog post Id) and creates a shortcode, pasting it into the editor.

Expanding the Blog Post Shortcode

The last item we need to define is the helper method to expand the blog post shortcode. For more on the shortcode expander helper methods, see the previous article Supporting Shortcodes in Sitefinity Content.

Add a new class to your project with the following static Expand method as shown here.

 public static string Expand(object inputText)
        {
            if (inputText == null) return string.Empty;
            var result = inputText.ToString();

            // use regex to find matches in the text
            string regex__1 = @"\[blogpost:.*?\]";
            MatchCollection matches = Regex.Matches(result, regex__1);

            // open the content and page managers 
            var mgr = BlogsManager.GetManager();
            var pageMgr = PageManager.GetManager();

            // parse through all shortcode matches in the text
            foreach (Match match in matches)
            {
                // extract the blog post id
                var blogPostId = new Guid(match.Value.Substring(10, match.Value.Length - 10 - 1));

                // find the matching blog post (if any)
                var blogPost = mgr.GetBlogPosts().FirstOrDefault(p => p.Id == blogPostId && p.Status == ContentLifecycleStatus.Live);
                if (blogPost == null) continue;

                // get parent blog
                var blog = blogPost.Parent;
                if (blog == null) continue;

                // get parent blog default url
                var defaultPage = blog.DefaultPageId;
                if (!defaultPage.HasValue) continue;
                var page = pageMgr.GetPageNode(defaultPage.Value);
                if (page == null) continue;

                // get blog post url
                var pageUrl = page.GetFullUrl();
                var fullUrl = string.Format("{0}{1}", VirtualPathUtility.ToAbsolute(pageUrl), blogPost.Urls.Where(u => u.RedirectToDefault == false).First().Url);

                // replace shortcode with link to blog post
                string player = string.Format(@"<a href=""{0}"">{1}</a>", fullUrl, blogPost.Title);
                result = result.Replace(match.Value, player);
            }

            return result;
        }

As the code shows, we first need to find the blog that matches the given Id, then use its default page property to build the Url. Finally, we use the default blog post Url to create the full link to the details view for the post and return it to the Content Block.

The result is a complete link to the blog post, complete with the actual post title, using only the simple blog post shortcode.

Sitefinity-Blog-Post-Shortcode-Expanded

Wrapping Up

Sitefinity's support for external widget templates is a powerful way to add custom functionality to your website. Combining this with the intuitive API unlocks unlimited possibilities for extensibility and customization. Try if for yourself today and be sure to share your customizations, as well as comments and suggestions with us in the Sitefinity discussion forums.

progress-logo

The Progress Team

View all posts from The Progress Team on the Progress blog. Connect with us about all things application development and deployment, data integration and digital business.

Comments

Comments are disabled in preview mode.
Topics

Sitefinity Training and Certification Now Available.

Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.

Learn More
Latest Stories
in Your Inbox

Subscribe to get all the news, info and tutorials you need to build better business apps and sites

Loading animation