Categories
josephscott

Blog ID in WordPress and XML-RPC Blog APIs

If you’ve done any sort of work with XML-RPC blog APIs on WordPress you’ve come across blog_id. What blog_id does and does not do in WordPress can be a bit confusing though.

Lets look at the metaWeblog.* XML-RPC methods to get an idea of what the problem looks like. Here’s the metaWeblog.newPost method:

metaWeblog.newPost( blog_id, username, password, struct, publish )

The WordPress implementation of this method doesn’t use the blog_id value at all. For all intents and purposes it is thrown away, only using the last four parameters. It’s kept in the parameter list though in an effort to be compatible with other implementations of metaWeblog.newPost.

For regular WordPress installs that isn’t too confusing. There is some very limited internal use of blog_id, just none at the XML-RPC level. Where things go a little side ways is with WordPress MU (WPMU), which is what WordPress.com uses. WPMU uses the blog_id value quite a bit, since it has to manage multiple blogs.

One reason for including the blod_id in method calls like metaWeblog.newPost is because other services only have one XML-RPC end point (end point is just a URL). One example is TypePad, whose XML-RPC end point is http://www.typepad.com/t/api. This allows them to figure which blog the new post is being assigned to. For WPMU there is a unique XML-RPC end point for each blog, instead of just one for the whole WPMU install. Because of this WPMU doesn’t need the blog_id value to figure out which blog the new post is for because it can figure that out from the XML-RPC end point being used.

But wait, there’s more. Here’s metaWeblog.editPost:

metaWeblog.editPost( post_id, username, password, struct, publish )

You’ll notice that there’s no blog_id in the parameter list. For other services this isn’t an issue because they’ll generate unique post_id values not for just one blog, but for their whole service. WPMU doesn’t do that, post_id’s are only unique in each blog. A given WPMU install could have as many posts with a post_id of 1 as there are blogs setup.

So far all of these examples can be addressed by making sure that you point to the correct XML-RPC end point. But the metaWeblog.* methods aren’t the only APIs WordPress makes available, there’s also a subset of the blogger.* methods. One that really causes grief is blogger.getUsersBlogs:

blogger.getUsersBlogs( app_key, username, password )

Ignore the app_key parameter, WordPress does. The intent of this method was to let clients know what blogs a given user had access to. Once the user provided a username and password a client could then just ask the service for a list of all the blogs that the user had access to. Unfortunately for WPMU, clients would make certain incorrect assumptions once they’d asked blogger.getUsersBlogs for information.

Let’s use example.com has an example of a multi-blog site. I’ve got blogs at joseph.example.com, josephscott.example.com and helloworld.example.com. A blog client comes along and asks example.com/xmlrpc.php for a list of blogs that I have access to. They get a list back that looks something like:

{
	{
		url: http://joseph.example.com/,
		blogid: 123123,
		blogName: Joseph
	},
	{
		url: http://josephscott.example.com/,
		blogid: 321321,
		blogName: "Joseph Scott"
	},
	{
		url: http://helloworld.example.com/,
		blogid: 90909090,
		blogName: "Hello World"
	}
}

Nothing wrong so far, but it’s what I see blog clients do next that breaks things. Instead of querying each blog URL to find out what the XML-RPC end point is for each one, they assume that the end point that provided this data will work for all three. I’ve found this to be a very common assumption in blog clients. In this case it means that they send metaWeblog.newPost requests to example.com/xmlrpc.php. For services that have one global end point for all of their blogs this works fine, which works because they send along the unique blog_id value. This doesn’t work for WPMU because it throws away those blog_id values sent to it via XML-RPC methods.

At this point you might be thinking, well, gee, why don’t you just fix WordPress/WPMU to respect the blog_id and then everything will be fine. That was what I thought the first time I ran into this. I started digging through code, and then I ran into metaWeblog.editPost (and others) that don’t require a blog_id value. That’s when I realized that it wasn’t realistic to try and fix this. It would require WPMU to generate unique post_id values across all blogs, something that it does not do, and isn’t likely to be doing in the near future.

In order to minimize the confusion I changed the behavior of the blogger.getUsersBlogs method in WordPress. Instead of sending details for all the blogs that the user had access to, it only sent info for the one blog that it was talking to. Continuing with the example above, lets say the client had sent a blogger.getUsersBlogs request to josephscott.example.com/xmlrpc.php. The response would only contain data about josephscott.example.com. This effectively prevents the client from getting confused about example.com supporting blog_id and only using one global XML-RPC end point. The down side to this approach is that instead of the client being able to discover all of the other blogs that I have access to on example.com, I have to configure each one in the client.

Well, that isn’t completely true. If a client makes a blogger.getUsersBlogs to the master blog in an WPMU install it will still get a list of all the blogs that user has access to. In the example above that would be example.com/xmlrpc.php. This was necessary because some services querying WordPress.com depended on this. Those changes were generalized and are included as part of WPMU.

For blog clients that wanted access to a user blog list but don’t make the single end point assumption I added a new method, wp.getUsersBlogs:

wp.getUsersBlogs( username, password )

It returns the same data that blogger.getUsersBlogs does, with one additional field for each blog: xmlrpc. The xmlrpc field is the XML-RPC end point for each blog. This saves the client from having to go out and detect the end point for each blog. My hope was that if a client knew enough to ask for wp.getUsersBlogs it also knew enough not to make incorrect assumptions about what to do with that data.

Right now the wp.getUsersBlogs is only available on WordPress.com, but it will be hitting WordPress and WordPressMU soon.

It’s still possible that at some point we’ll do enough low level work in WordPress/WPMU to make things work in a manner similar to what others do with blog_id and post_id, but for now this is where things stand. If you are making use of the XML-RPC APIs in WordPress and wondered what the story was with blog_id’s, now you know.