Making your own blog engine <tutorial>

While everybody seems to be using WordPress right now, there’s no reason not consider making your own blogging platform. In this blog post, I’m sharing my experience on the creation of a blogging platform.

Firstly, you may ask yourself why you need anything special to write your own blog engine. After all, don’t you really need something else than an online editor? If it’s really what you think, that’s fine. However, if you like using external programs like the excellent Windows Live Writer, you’ll need a web service to interface your platform.

Creating your own blog platform is not so complex. I managed to create my own in only one day of work (admittedly, I didn’t leave the computer until it worked!). However, there’s no real specification out there explaining clearly how your web service should work.

WordPress: a mold giving form to all others

The truth about blogging platforms is that they have to follow the WordPress API to work correctly. However, if you don’t need the full capabilities of the WordPress API, there’s a reasonable subset to work with called MetaWeblog. This is the one I decided to support.

For the previously noted reasons, to create your blog engine, I strongly recommend you to reverse engineer someone else’s engine. I personally reverse-engineered WordPress, even if I limited myself to the functions which made sense in my case.

The source code of my blogging platform is freely downloadable here. In case you don’t plan to support more than the functionalities I talk about in this blog, it will be far easier to use this as your base because it has less legacy code than WordPress and functions are much smaller.

In the rest of this blog post, I’ll try to give you enough information to quickly grasp how this all work.

XML RPC

Basically, all blogs API are based on XMLRPC, an old standard for making remote procedure calls. If you want my opinion on XMLRPC, here’s it it: this is the worst web service API I ever had to work with: it doesn’t work as fast as a binary call, it isn’t readable as a JSON call and doesn’t provide you as much features as SOAP.

To work with XML RPC, I decided to go the WordPress way, and use the Incutio XML-RPC Library for PHP. There are however already working implementations, for example in C#. When you decide to use an abstraction for the message protocol, things becomes much easier.

API Essentials

The essential procedures of MetaWeblog are:

newPost(
     blogID as String,
     username as String,
     password as String,
     content as PostStruct,
     published as Int32
) as (
     postID as String
)

editPost(
    postID as String,
    username as String,
    password as String,
    content as PostStruct,
    published as Int32
) as (
        ok as Boolean
)

getPost(
    postID as String,
    username as String,
    password as String
) as (
    content as PostStruct
)

deletePost(
    postID as String,
    username as String,
    password as String
) as (
    ok as Boolean
)

Blog posts are described using the PostStruct, which looks like this:

PostStruct as (
    postid as String,
    link as String,
    title as String,
    description as String,
    categories as StringArray,
    …
)

where description refers to the HTML content of you message.

Clients also use this function to verify your credentials, so you need to implement it:

getUsersBlog(
    blogID as String,
    username as String,
    password as String
) as (
    blogID as String,
    blogName as String,
    is_admin as Boolean
)

Working with images

To support image upload, you also need to support this procedure :

newMediaObject(
    blogID as String,
    username as String,
    password as String,
    data as (
        fileName as String,
        fileMimeType as String,
        bits as ByteArray
    )
) as (
    url as String,
    type as String,
    name as String
)

Usability issues

Smart readers will notice that it’s impossible to know which post is linked to the uploaded images. Therefore, I recommend you to save your files in such a way that you can filter them by date to delete the ones you don’t need anymore.

Also, security-aware readers will wonder if the password is really sent in clear in every procedure call and, unfortunately, the response is yes. I recommend you to use a unique password for your blog if you plan to use it on unknown networks. Also, using HTTPS is a must for important (read: non-personal) blogs.

I recommend you to support those calls prefixed with two namespaces: blogger.xxx and metaWeblog.xxx. Clients like Windows Live Writer may use both to name methods.

Advertising MetaWeblog support

Supporting an API is nice but most clients will require you to either advertise your API location or provide it manually. I think the best experience is to provide the clients with an indication of where they can find the API.

On my blog, I followed the indications found on Windows Live Writer website. Here’s what it looks like :

<link rel="EditURI" type="application/rsd+xml" href="./API/xmlrpc/?rsd=1" />
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="./wlwmanifest.xml" />

Here’s what a RSD (Really Simple Discovery) file looks like :

<?xml version="1.0" encoding="utf-8"?>
<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
  <service>
    <engineName>NoDB-Blog</engineName>
    <engineLink>http://fremycompany.com</engineLink>
    <homePageLink>http://fremycompany.com/BG/</homePageLink>
    <apis>
      <api 
        name="MetaWeblog" blogID="1" preferred="true" 
        apiLink="http://fremycompany.com/BG/API/xmlrpc/" 
      />
    </apis>
  </service>
</rsd>

And here’s my Windows Live Writer manifest:

<?xml version="1.0" encoding="utf-8" ?> 
<manifest xmlns="http://schemas.microsoft.com/wlw/manifest/weblog">
    <options>
        <clientType>Metaweblog</clientType>
        
        <supportsCustomDate>No</supportsCustomDate>
        <supportsExcerpt>Yes</supportsExcerpt>

        <supportsEmptyTitles>No</supportsEmptyTitles>
        <supportsNewCategories>Yes</supportsNewCategories>
        <supportsNewCategoriesInline>Yes</supportsNewCategoriesInline>
        
        <supportsEmbeds>Yes</supportsEmbeds>
        <supportsScripts>Yes</supportsScripts>
        
        <characterSet>utf-8</characterSet>
        <requiresHtmlTitles>Yes</requiresHtmlTitles>
        
        <invalidPostIdFaultCodePattern>404</invalidPostIdFaultCodePattern>
        
    </options>
    <weblog>
        <serviceName>FC NoDB-Blog</serviceName>
    </weblog>
    <views>
        <default>WebLayout</default>
        <view type="WebLayout"  src="…/template.wlw1.html" />
        <view type="WebPreview" src="…/template.wlw2.html" />
    </views>
</manifest>

Working with categories

If, like me, you want to be able to tag your posts, you may want to support three other APIs:

metaWeblog.getCategories(…) as StringArray
wp.newCategory(…)
wp.deleteCategory(…)

As the two last ones are WordPress functions, your client will probably not use them by default if you advertised MetaWeblog support. It will either try to add unknown categories to you post data or will not allow you to do so.

This is for example the case of WLW. The solution to this problem is to explicitly allow WLW to call them, by adding a “wlwmanifest.xml” file to your blog. You can find more information about this manifest on their website. It’s possible that other clients may use it, if it’s present.

Issues I wasn't able to solve

As good as my implementation was, I wasn’t able to get WLW automatically generate a short description of my blog post (I generated it myself based on its first paragraph, and I can edit it manually on WLW, but this isn’t the nice, automatic solution I wanted.

Also, for some unknown reason, I didn’t find a way to delete from the server a draft I published there using WLW from WLW. I need to do it manually on the server.

Concluding

This was a fun experiment, and I’m happy to have my own blogging engine at this time. This is still a work in progress, but this is a good one. Also, just because adding images is so addictive, here’s one of them!

Pharaons déchus
Supercool!

Thank you for reading this blog post, I hope you learned something!

Published on 2012-06-24 under ALL, WEB

Comments

A javascript file is loading the comments.