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.

12 replies on “Blog ID in WordPress and XML-RPC Blog APIs”

Thank you for this. I have a question: how do you get the blog_id for WPMU blogs when doing an XMLRPC post? Like where do you find it? Is it simply the “subdomain” that the WPMU blog is on?

Thanks, I was able to get the blog_id that way, but everytime I try to do a metaWeblog.newpost request, it throws back an error. The website I’m trying to submit to has WPMU-1.0. Has the metaWeblog support only been added after 1.0? The blogger API works fine.

I know it’s old, but it’s not my website, so I really don’t have a choice of upgrading :). But yea, do you happen to know if metaweblog api support has only been added after 1.0?

Do you know of any way to add a timestamp to posts done to WPMU-1.0? That is what I’m basically trying to do…

Very cool. Thanks for the info — very timely as I’m just getting started with XML-RPC and WordPress app development.

Where can I find documentation on the methods available?

thanks much

tom

I see that this fix is in WPMU now, but I am still experiencing problems with blogging clients as if the fix is not there. One diff, I note, is that you discuss subdomains but I am using subdirectories in my installation… do you think that could cause problems with the fix?

Both Livewriter and Scribefire are having the same problems discussed pre-fix. I posted here: http://mu.wordpress.org/forums/topic.php?id=6235#post-57161

Hello every one im using this code,, im junior programmer and this is my first time to use xmlrpc, im just wondering why i get this error -> Got invalid response… Maybe i miss something in my code or i don’t know

return_type = ‘xml’;
// let’s the native xmlrpc extension take care of encoding request parameterss
$r = $c->send(xmlrpc_encode_request(‘wp.getUsersBlogs’, $_POST[‘stateno’]));
if ($r->faultCode())
// HTTP transport error
echo ‘Got error ‘.$r->faultCode();
else
{
// HTTP request OK, but XML returned from server not parsed yet
$v = xmlrpc_decode($r->value());
// check if we got a valid xmlrpc response from server
if ($v === NULL)
echo ‘Got invalid response’;
else
// check if server sent a fault response
if (xmlrpc_is_fault($v))
echo ‘Got xmlrpc fault ‘.$v[‘faultCode’];
else
echo’Got response: ‘.htmlentities($v);
}
?>

Leave a Reply

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