.NET and Open Source: better together

RTur.net

  • Join Us on Facebook!
  • Follow Us on Twitter!
  • LinkedIn
  • Subcribe to Our RSS Feed

Building Widgets for BlogEngine.NET 3.3

Version 3.3 dropped user controls from BlogEngine and new widgets use Razor views instead. To start developing new widget, open source code in Visual Studio, navigate to BlogEngine.NET/Custom/Widgets in the solution explorer and add "Example" folder. If you run application and go to admin/custom/widgets, you'll see "Example" widget added to available widgets. You can even drag it to widget zone and save changes.

But because we don't have any code to support this widget, in the website you'll see an error instead of actual widget. It explains what file BlogEngine is looking for - "widget.cshtml" in that newly created folder.

So go back to Visual Studio and add widget.cshtml file. Here is a code for it:

@{
    var title = Model.Title;
}
<div class="widget tagcloud">
    <h4 class="widget-header">@title</h4>
    <div class="widget-content">
        This is an example. Widget ID is @Model.Id
    </div>
</div>

Few things to understand in this code. It is very simple standard Razor view and BlogEngine passes Model object into the view as one would expect. This is very simple object indeed, it has only 2 properties: Title and Id. If you save your code and reload website, you should see your widget in the sidebar in all glory.

The title is the name of your folder, in this case "Example". The Id created when you drag-and-dropped widget into widget zone. With XML provider, it added line to the widget zone file under app_data/datastore/widgets. With database provider, it would update a record in the table. So there is no mystery here.

Even with this little knowledge, you already can do some useful things. For example, most social sites provide some kind of code widgets you can copy/paste in your blog as HTML - you could add this code to widget.cshtml and be done. Also, BlogEngine exposes many useful objects and events and they all available to you in the server-side code block. The code below shows how you can easily output number of posts and blog title pulling data from server-side code.

@{
    var title = Model.Title;
    var postCnt = BlogEngine.Core.Post.ApplicablePosts.Count;
    var blogName = BlogEngine.Core.BlogSettings.Instance.Name;
}
<div class="widget tagcloud">
    <h4 class="widget-header">@title</h4>
    <div class="widget-content">
        <p>Posts in the blog: @postCnt</p>
        <p>Blog title: @blogName</p>
    </div>
</div>

Here what you should see in the browser now:

This lets you create many simple widgets, but often you would want to provide customization. For this, your widget needs settings. Currently, if you click on pencil icon in the widget admin, it will only let you change title. To add settings page, we need to add "edit.cshtml" to the Example folder. The name follows convention and is what BlogEngine expects to find. So in Visual Studio, add "edit.cshtml" with code as below:

<!DOCTYPE html>
<html>
<body class="widget-edit">
    <div class="widget-edit-commentlist">
        <form method="post">
            <div class="form-group">
                <label>Example setting</label>
                <input type="text" class="form-control" id="txt1" name="txt1" value="" />
            </div>
            <button type="submit" class="btn btn-success">@Resources.labels.save</button>
        </form>
    </div>
</body>
</html>

Now if you open settings page in admin, this will look like this:

So we got our setting, but it is kinda ugly. To fix, we need to include some styles:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="~/Content/bootstrap.min.css">
    <link rel="stylesheet" href="~/Content/font-awesome.min.css">
    <link rel="stylesheet" href="~/admin/themes/standard/css/styles.css">
</head>

And it looks much better now.

With visuals in place, next thing is to be able save this setting and read it back. Modify edit.cshtml to look like code below:

@using BlogEngine.NET.Custom.Widgets
@{
    var exampleSetting = "This is an example";
    var widgetId = Request.QueryString["id"];
    var settings = Common.GetSettings(widgetId);
    if (IsPost)
    {
        settings["examplesetting"] = Request.Form["txt1"];
        Common.SaveSettings(settings, widgetId);
        @:<script type="text/javascript">window.parent.toastr.success("Completed");</script>
    }
    if (settings != null && settings.Count > 0)
    {
        exampleSetting = settings["examplesetting"];
    }
}
<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="~/Content/bootstrap.min.css">
    <link rel="stylesheet" href="~/Content/font-awesome.min.css">
    <link rel="stylesheet" href="~/admin/themes/standard/css/styles.css">
</head>
<body class="widget-edit">
    <div class="widget-edit-commentlist">
        <form method="post">
            <div class="form-group">
                <label>Example setting</label>
                <input type="text" class="form-control" id="txt1" name="txt1" value="@exampleSetting" />
            </div>
            <button type="submit" class="btn btn-success">@Resources.labels.save</button>
        </form>
    </div>
</body>
</html>

There few things to explain in this code. First of, we included custom/widgets namespace and introduced local variable "exampleSetting". This variable represents value we want to be able type in the textbox and save. We need to know widget ID to be able to save and retrieve settings for this widget, and ID always passed into edit page by BlogEngine  as query string (line #4), so we use it to get settings object (line #5). This object provided by BlogEngine, and we don't care where and how it saves our value as long as we can save and get it back.

Before we save settings, widget will be using declared in the line #3 as default. But if I click "save" button, the code in the "if (IsPost)" block will be executed (lines 8-10). This will take value fro texbox, save it and display confirmation message.

And I can use code similar to above to use this setting in my Example widget:

@using BlogEngine.NET.Custom.Widgets
@{
    var exempleSetting = "Default value";
    var settings = Common.GetSettings(Model.Id);
    if (settings != null && settings.Count > 0)
    {
        exempleSetting = settings["examplesetting"];
    }
}
<div class="widget example">
    <h4 class="widget-header">@Model.Title</h4>
    <div class="widget-content">
        <p>Setting value: @exempleSetting</p>
    </div>
</div>

Which suppose to produce output in the browser similar to the picture below.

The widget settings allows to save multiple values and use them to customize your widget with anything it needs, like width, height, number of items, color and so on.

This is the first tutorial on widgets to get you started. Next time we can check things like input validation and publishing to the gallery.

Example.zip (1.04 kb)