Building A Web App – WordPress Integration

Note: This is a continuation of a series of posts on the design and development of a web application for a non-profit organization. Previous posts:

The goal of this post is to fetch WordPress content and place it with in our ‘home page’. This is shown in the image below. The content surrounded by the red square is stored by WordPress but is being rendered in our page.

image

This content can be accessed directly in WordPress and looks like the following:

image

The issue with viewing is in WordPress is that we are navigated away from our ‘home page’ to a page that looks like a blog. We could theme up our blog to look like our ‘home page’ but that seems like a waste of time. Besides, for the site blog I want it to have more of a blog feel.

Design Goals

Two major design goals of this web application are:

  1. To have a ‘home page’ for the web site that provides a platform for extension. For this reason, I chose to have an ASP.NET MVC front end.
  2. To allow the end user (not me) to generate content for the web site. I cannot continue to do new things if I have to heavily support the application by generating content.

The last point is an important design consideration. I really do not want to generate site content. I much prefer to develop the site framework and add new site features. This requires that the design empowers the end user to do this for themselves. Most end users are not as technical as developers, so this would fail miserably if we don’t provide the right tooling.

WordPress Blog Engine

The WordPress blog engine is quite mature and stable. It is also supported by my hosting environment. Many sites use WordPress as their ‘home page’. Because of WordPress’ maturity, there exists a lot of tooling to enable users to easily create content. Although WordPress is very extendable (via plugins), the server side code is PHP. Nothing wrong with PHP, at this time it is just not high on my skill set.

WordPress can save content in two formats: post and page. A post is simply a new entry in the blog. A page is equivalent to a post, except it stand alone and is not shown in the blog. Our site will have a number of these stand alone pages that will be accessed via our ‘home page’.

WordPress actually saves both ‘post’ and ‘page’ content to the same database table. The underlying implementation uses a database field to distinguish between the two.

Our web application will be using WordPress to provide the following:

  • Content Database – Because WordPress is a blog engine, it can store post / page content. This is a real time saver in the design. Imagine if I had to develop my own content database.
  • Blog Engine – The site’s blog will use WordPress. This falls right into WordPress’ strengths.

WordPress is free and it is easy to get started. In fact WordPress, will host your blog content for you. WordPress can be customized in a number of ways:

  • Theme – You can select from thousands of free WordPress themes.
  • Plugins – You can extend the WordPress by installing free plugins. These plugins add features to the blog engine. For instance you can add Akismet (anti-spamming), CAPTCHA (are you human) and Twitter Widgets.
  • Code – You can also modify CSS, HTML and PHP to create the ultimate WordPress site.

The one plugin that is required in this post is the “Reveal IDs for WP Admin” plugin. This plugin reveals the page / post IDs (normally hidden) on the admin page. These will be used later to query for page / post content.

XML-RPC, MetaWeblog API and WordPress

Most blog engines support some sort of API that can be used to programmatically access and add content. WordPress supports the XML-RPC communication protocol. XML-RPC is a communication protocol that allows software running on disparate operating systems to make calls over the internet. It’s remote procedure calling using HTTP as the transport and XML as the encoding. MetaWeblog application programming interface allows external programs to get and set text and attributes of weblog posts. MetWeblog API is built on top of the XML-RPC communication protocol.

There already exists .NET wrapper around the XML-RPC protocol. The one most commonly used was created by Charles Cook and can be download here. WordPress has extended the MetWeblog API with their own WordPress API. Once again there already exists a nice WordPress wrapper created by Alex James Brown called Joe Blogs.

After completing this implementation I realized that the XML-RPC code that Charles Cook developed uses .NET reflection. So this solution will not work in my medium trust deployment environment. This is great example of why we should code to interfaces. I will be working on an implementation of the IWordPressRepo interface that does work in medium trust. I will post that implementation at a later time.

In the code below I will be using these two libraries to interface with WordPress. Instead I will be implementing some code to directly query the database (see database section below).

WordPress MVC Model and Repository

The WordPress content that I am currently rendering in my view is only the page (or post) title and description. The following model encapsulates that content:

public class PostData
{
    public string Title { get; set; }
    public string Details { get; set; }
}

I created the following WordPress repository interface to handle fetching post and page content:

public interface IWordPressRepo
{
    PostData GetPost(string id);
    PostData GetPage(string id);
}

Having an interface is key to allowing the controller to be tested using a fake instance of the IWordPressRepo interface. In addition this interface encapsulates the implementation of the XML-RPC / MetaBlog interface. If a better API is introduced by WordPress, our code changes are isolated to the concrete implementation of the IWordPressRepo interface.

XML-RPC WordPress Repository Implementation

As noted above the following implementation will not work in a medium trust environment. I will keep the code in the blog post for those who can use it. If you are deploying to a medium trust server, you should use the database implementation described in the next section.

The following is the concrete implementation of the WordPress repository:

public class WordPressRepo : IWordPressRepo
{
    private readonly WordPressWrapper _wpWrapper;

    public WordPressRepo(string xmlRpcUrl, string userName, string passWord)
    {
        _wpWrapper = new WordPressWrapper(xmlRpcUrl, userName, passWord);
    }

    public PostData GetPost(string id)
    {
        Post post;
        try
        {
            post = _wpWrapper.GetPost(id);
        }
        catch
        {
            // Word press exception. Stuff in some diagnositics.
            //
            post.title = "Content Not Found";
            post.description = "Could not find any content with id=" + id;
        }

        PostData postData = new PostData
                                {
                                    Title = post.title,
                                    Details = post.description
                                };
        return postData;
    }

    public PostData GetPage(string id)
    {
        Page post;
        try
        {
            post = _wpWrapper.GetPage(id);
        }
        catch
        {
            // Word press exception. Stuff in some diagnositics.
            //
            post.title = "Content Not Found";
            post.description = "Could not find any content with id=" + id;
        }

        PostData postData = new PostData
                                {
                                    Title = post.title,
                                    Details = post.description
                                };
        return postData;
    }
}

The above repository leverages the “WordPressWrapper” that can be found in the Joe Blogs code. The constructor of the repository instantiates an instance of the “WordPressWrapper” object. Then two methods fetch either the post or page data. These two methods are almost identical except for the method called on the “WordPressWrapper” object. A bit of error handling is introduced to take care of the cases where the call to the “WordPressWrapper” method throws an exception. Finally, the WordPress data is repackaged into our model object and returned.

Database WordPress Repository Implementation

The database that WordPress leverages is a MySQL database. There is a MySQL .NET connector that is a fully managed ADO.NET driver for MySQL. Installing this connector will provide you with a “MySql.Data.dll” that you should reference in your application. Because I will be providing my own data access layer, I have added a few properties to the “PostData” and “IWordPressRepo” interface that we previously defined. I know that in the future, I will want to be able to display a list of most recent blog posts on the ‘home page’ so I am preparing for the future. Here is the new “PostData” and “IWordPressRepo” definitions:

public class PostData
{
    public int Id { get; set; }
    public DateTime TimeStamp { get; set;}
    public string Title { get; set; }
    public string Details { get; set; }
    public string Author { get; set; }
}

public interface IWordPressRepo
{
    PostData GetPost(string id);
    PostData GetPage(string id);
    List<PostData> GetRecentPosts(int count);
}

You will need the connection string for your MySQL database. Here are instructions for getting this from GoDaddy. Add this information to your Web.Config in the connection strings section. The following is the concrete implementation of the IWordPressRepo that works in medium trust:

public class WordPressRepo : IWordPressRepo
{
    private const string _select = "SELECT wp_posts.ID, wp_posts.post_date, wp_posts.post_title, wp_posts.post_content, wp_users.display_name FROM wp_posts INNER JOIN wp_users ON wp_posts.post_author=wp_users.ID ";
    private readonly string _connnectionString;

    public WordPressRepo(string connectionString)
    {
        _connnectionString = connectionString;
    }

    public PostData GetPage(string id)
    {
        return GetPost(id);
    }

    public PostData GetPost(string id)
    {
        string sql = _select + "WHERE wp_posts.post_status='publish' && wp_posts.ID=" + id;

        return GetSingle(sql);
    }

    public List<PostData> GetRecentPosts(int count)
    {
        string sql = _select + "WHERE wp_posts.post_type='post' && wp_posts.post_status='publish' ORDER BY wp_posts.post_date DESC LIMIT " + count;

        return GetCollection(sql);
    }

    private PostData GetSingle(string sql)
    {
        MySqlConnection connection = new MySqlConnection(_connnectionString);
        MySqlCommand command = connection.CreateCommand();

        command.CommandText = sql;
        connection.Open();
        MySqlDataReader reader = command.ExecuteReader();
        PostData result = null;
        if (reader.Read())
        {
            result = ParseData(reader);
        }
        connection.Close();

        return result;
    }

    private List<PostData> GetCollection(string sql)
    {
        MySqlConnection connection = new MySqlConnection(_connnectionString);
        MySqlCommand command = connection.CreateCommand();

        command.CommandText = sql;
        connection.Open();
        MySqlDataReader reader = command.ExecuteReader();
        List<PostData> result = new List<PostData>();
        while (reader.Read())
        {
            PostData post = ParseData(reader);
            result.Add(post);
        }
        connection.Close();

        return result;
    }

    private static PostData ParseData(IDataRecord reader)
    {
        PostData result = new PostData
                              {
                                  Id = reader.GetInt32(0),
                                  TimeStamp = reader.GetDateTime(1),
                                  Title = reader.GetString(2),
                                  Details = reader.GetString(3),
                                  Author = reader.GetString(4)
                              };
        return result;
    }
}

For what I need to do, the above code is less complex and easier to maintain than the XML-RPC / Joe Blogs code. There was a lot of code under the hood of those libraries that can be replaced by the code above.

One side effect of using the above code is that I will need a local copy of my WordPress database for development. The database hosted by GoDaddy cannot be accessed from the outside.

MVC Blog Controller

The following is the blog controller that handles the request for the WordPress page and uses the database version of the WordPress repo:

public class BlogController : Controller
{
    private readonly IWordPressRepo _wordPressRepo;

    public BlogController()
    {
        _wordPressRepo = new WordPressRepo(ConfigurationManager.ConnectionStrings["WordPress"].ConnectionString);
    }

    public BlogController(IWordPressRepo wordPressRepo)
    {
        _wordPressRepo = wordPressRepo;
    }

    public ActionResult Post(string id)
    {
        if (!string.IsNullOrEmpty(id))
        {
            return View(_wordPressRepo.GetPost(id));
        }
        return new EmptyResult();

    }

    public ActionResult Page(string id)
    {
        if (!string.IsNullOrEmpty(id))
        {
            return View("Post", _wordPressRepo.GetPage(id));
        }
        return new EmptyResult();

    }
}

The blog configuration data at the top of the page is probably best placed in a config file (and no that is not my real username and password). Since I don’t anticipate these changing, I have opted to KISS it. There are two constructors. The parameterless constructor is used by the MVC framework to instantiate an instance of the controller. This constructor creates an instance of the “WordPressRepo” that we already discussed. The second controller is used by testing frameworks and allows a fake “IWordPressRepo” instance to be injected.

There are two action methods on this controller: Post and Page. They are nearly identical except for the method called on the “IWordPressRepo” object. In both cases the “PostData” model returned by the “IWordPressRepo” instance is injected into the “Post” view.

MVC Post View

The following is the view used by the above controller:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Heartland.Models.PostData>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    <%= Model.Title%>
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<div class="post round">

    <div class="post-wrap">

        <h1 class="headline"><%= Model.Title %></h1>

        <div class="content">
            <%= Model.Details %>
        </div>

    </div>

</div>

</asp:Content>

First notice the view is using a master page. This provides the content for all the content surrounding the view. Also note that the generic ViewPage uses the PostData type for the model.

The other content is displays the title in an “h1” tag and the content in a “div”. Note that both the title and the content are allowed to have HTML content. This information has been wrapped in “div" tags and styled with class attributes. The following CSS is used to style the content:

div.post
{
    font-size: 120%;
    line-height: 2.0;
    font-family: Helvetica;
    background-color: #eee;
    padding: 10px;
}

div.post div.post-wrap
{
    width: 560px;
    margin: 0 auto;
    background-color: #eee;
    color: #333;
}

div.post h1, div.post h2, div.post h3, div.post h4, div.post h5, div.post h6
{
    margin: 10px 0 0;
}

div.post h1.headline
{
    margin: 10px 0;
    padding: 3px 10px;
    background-color: #193C74;
    font: bold 26px Helvetica, sans-serif;
    color: #8dc3e9;
}

div.post div.content
{
    font-size: 120%;
}

div.post a
{
    color: #215c97;
}

div.post a:hover
{
    color: #ccc;
    text-decoration: underline;
}

div.post h1
{
    font: bold 26px Helvetica, sans-serif;
    letter-spacing: -1px;
}

div.post h1 a
{
    color: #666;
    display: block;
}

div.post h1 a:hover
{
    color: #215c97;
    text-decoration: none;
}

div.post h2
{
    font: bold 150% Georgia, serif;
    margin: 0 0 10px 0;
}

div.post h2.archive-title
{
    margin: 10px 0 0 20px;
    font: bold 26px Helvetica, sans-serif;
    color: #215c97;
}

div.post h3
{
    font: italic 120% Georgia, serif;
    margin: 0 0 5px 0;
}

div.post ul, ol
{
    margin: 0 0 20px 20px;
}

div.post blockquote
{
    background-color: #ddd;
    border: 1px solid #888;
    margin: 10px;
    padding: 10px;
}

Using the Blog Controller

Now it is easy to add a link to our ‘home page’ using the following:

<%= Html.ActionLink("What is Heartland?", "Page", "Blog", new { id = "2" }, null)%>

This above is a script tag from ASP.NET MVC that uses the ActionLink extension method to create a link. The parameters are:

  • link title = “What is Heartland?”
  • action method = “Page”
  • controller = “Blog”
  • id (part of the default routing) = “2” (in the above case)

This will create a link that looks like the following:

<a href="/Blog/Page/2">What is Heartland?</a>

The trick here is to determine the value for “id”. This is done using the “Reveal IDs for WP Admin” plugin that we installed in WordPress. Now the ID can be seen on the WordPress admin panel as shown below:

image

 

Summary

After a bit of work, the end user of this web site can now create pages / posts in WordPress and have the content appear in the ‘home page’. This allows the content to be surrounded by other non-blog (think about the side bar that is typically in a blog…look to the right) content. This little bit of effort goes a long way towards making the site have a consistent and more professional appearance.

Tags:,
Comments
  1. Paul

Leave a Reply

Your email address will not be published. Required fields are marked *

*