Your Ad Here

Tuesday, November 29, 2011

Automatic Post Creation with Wordpress, PHP, and XML-RPC


Automatic Post Creation with Wordpress, PHP, and XML-RPC

So, for those of you who read my last blog post, you might notice that I was having issues with a script I wrote to create a new post in Wordpress when it came time to upgrade the Wordpress code.  The SQL internals were modified, and I was inserting directly in to the database (yes, I know, I broke a cardinal rule).  I needed an alternative way to insert information in to the database that would be much more future-proof.  I remembered about XML-RPC.
It took me some time to find answers to questions I had about XML-RPC and the Wordpress’ API.  Wordpress comes with the ability to use XML-RPC, and AtomPub.  With regards to XML-RPC, it supports a few protocols:
  1. MetaWeblog
  2. Movable Type
  3. Blogger
  4. Wordpress’ own methods
Since there was little written documentation as to how to do this, I thought I’d share my findings.  Also, although the Blogger API was very easy to figure out and use, I’m not going to cover it here mainly because it doesn’t support the creation of a title field – something for my purposes were required.  (To access the blogger API, I used this class.)  I’m also only going to cover what’s necessary to create a new post for my own means, nothing more – hopefully it’ll get you on your way to how you’d like to use it.

One thing to note: In order for this to work, your version of Wordpress will have to have “Remote Publishing” enabled; depending on which protocol(s) you’ll be using, you’ll want to enable either “Atom Publishing Protocol” or “XML-RPC”, or both. This can be found (as of Wordpress version 2.7) under “Settings” and then “Writing”.
Let’s get to some nitty-gritty. The following XML-RPC methods are allowable with Wordpress (again, version 2.7):
Wordpress API:
  1. wp.getUsersBlogs
  2. wp.getPage
  3. wp.getPages
  4. wp.newPage
  5. wp.deletePage
  6. wp.editPage
  7. wp.getPageList
  8. wp.getAuthors
  9. wp.getCategories
  10. wp.getTags
  11. wp.newCategory
  12. wp.deleteCategory
  13. wp.suggestCategories
  14. wp.uploadFile
  15. wp.getCommentCount
  16. wp.getPostStatusList
  17. wp.getPageStatusList
  18. wp.getPageTemplates
  19. wp.getOptions
  20. wp.setOptions
  21. wp.getComment
  22. wp.getComments
  23. wp.deleteComment
  24. wp.editComment
  25. wp.newComment
  26. wp.getCommentStatusList
Blogger API:
  1. blogger.getUsersBlogs
  2. blogger.getUserInfo
  3. blogger.getPost
  4. blogger.getRecentPost
  5. blogger.getTemplate
  6. blogger.setTemplate
  7. blogger.newPost
  8. blogger.editPost
  9. blogger.deletePost
MetaWeblog API:
  1. metaWeblog.newPost
  2. metaWeblog.editPost
  3. metaWeblog.getPost
  4. metaWeblog.getRecentPosts
  5. metaWeblog.getCategories
  6. metaWeblog.newMediaObject
  7. metaWeblog.deletePost
  8. metaWeblog.getTemplate
  9. metaWeblog.setTemplate
  10. metaWeblog.getUsersBlogs
MovableType API:
  1. mt.getCategoryList
  2. mt.getRecentPostTitles
  3. mt.getPostCategories
  4. mt.setPostCategories
  5. mt.supportedMethods
  6. mt.supportedTextFilters
  7. mt.getTrackbackPings
  8. mt.publishPost
Wordpress also supports pingback, supposedly as an API. As for the AtomPub API, I don’t really understand that one yet, so if you want to find out what’s supported, you’ll want to look through the wp-app.php file found in your main Wordpress folder. The XML-RPC methods can be found in the xmlrpc.php file, also found in the main Wordpress folder.
As you can see, the Wordpress API is jam-packed with features – I believe most desktop applications that allow you to moderate your comments use the Wordpress API. Unfortunately, no “New Post” option for our needs. Dang. Because of this, and also because the Blogger API doesn’t support the creation of a title field in a new post, I decided to go with the MetaWeblog API. Technically speaking, MovableType and AtomPub are superior options to both Blogger and MetaWeblog from what I’ve been reading; regardless of that (possible) fact, I found it easy to work with the MetaWeblog API.
Let’s get to the code…
Umm…can PHP handle the transformation from data to the XML-RPC protocol of our choice automatically?
Unfortunately, no. However, the creators of Wordpress’ API features thought ahead. They packaged Wordpress with certain features and functionality (and classes) that can be utilized by us mere mortals to achieve our goals. Many of these libraries (such as the one we’ll use) were written by those not affiliated with Wordpress – so they took the legwork of finding good, well-written libraries for us.
We’ll be using the Incutio XML-RPC Library for PHP created by Simon Willison. You could download this yourself and include it in your script (note: commenter believes the official download to be corrupted), or you could just use what Wordpress already has in its folder structure, it’s the same thing with a few (pertinent) modifications and a different file name. (Wordpress uses it internally for some features since it works as a client and a server.)
The file is class-IXR.php, found in your wp-includes folder. So, to start out, we’ll create a PHP file that includes that script. We’ll also need to instantiate a new client object (to talk to the XML-RPC server – aka Wordpress). To find out what the address of your Wordpress XML-RPC server is (in order to instantiate the client), after you’ve enabled the XML-RPC remote publishing in your Wordpress settings, go to your Wordpress blog (any non-admin page) and view the source.
<link rel=”EditURI” type=”application/rsd+xml” title=”RSD” href=”http://www.example.com/xmlrpc.php?rsd />
You’ll want to take the URL from the HREF property of that line of code and place it in your browser. The rendered XML of the page gives us information as to the target URI for the protocol(s) we’d be using. If you’ll be using multiple protocols that use multiple targets, you’d have to target them each individually when making client calls. So, on to the fun stuff…
1include('/wp-includes/class-IXR.php');
2$client = new IXR_Client('http://www.example.com/xmlrpc.php');
This includes our XML-RPC library, allowing us to create a client connection. It then uses (defines) the target server access point for our client to access the APIs we aim to use. xmlrpc.php supports Wordpress, MovableType, MetaWeblog, and Blogger APIs all in one access point which makes it very easy if you want to use any or all four of them with the same IXR_Client object instantiation. Let’s build on that some more.
view sourceprint?
1include("../wp-includes/class-IXR.php");
3
4if (!$client->query('wp.getCategories','', 'admin','password')) {
5    die('An error occurred - '.$client->getErrorCode().":".$client->getErrorMessage());
6}
7$response = $client->getResponse();
This extra code now tells our client to query our server for the Wordpress API’s “getCategories” method using the username of “admin” with a password of “password”. If any errors occur, the script will stop execution after printing the error codes and messages supplied by Wordpress’ API server. If it’s successful, the server’s response is stored in the $response variable.
Taking a step back, the getCategories method takes on 3 parameters. I left one blank simply because Wordpress (as of version 2.7) does not require the BlogID field (WPMU might, however). The 3 parameters are BlogID, Username, and Password. It will authenticate the user before allowing information to be returned.
The Wordpress API is quite easy (or at least for the getCategories method anyway), it simply returns a PHP structured array. An example print_r output from the $response variable would look like the following:
01Array
02(
03    [0] => Array
04        (
05            [categoryId] => 1
06            [parentId] => 0
07            [description] =>
08            [categoryName] => Uncategorized
09            [htmlUrl] => http://127.0.0.1/wordpress/category/uncategorized/
10            [rssUrl] => http://127.0.0.1/wordpress/category/uncategorized/feed/
11        )
12)
That’s pretty darn easy to break down to values we might need! Now, moving on, let’s add some code to create a new post.
1$content['title'] = 'Test Draft Entry using MetaWeblog API';
2$content['categories'] = array($response[1]['categoryName']);
3$content['description'] = '<p>Hello World!</p>';
4if (!$client->query('metaWeblog.newPost','', 'admin','password', $content, false)) {
5    die('An error occurred - '.$client->getErrorCode().":".$client->getErrorMessage());
6}
7echo $client->getResponse();    //with Wordpress, will report the ID of the new post
This code sets up our desired blog title, the category we wish to use (in string format, do not use the ID value), the body of the blog post, and then queries the XML-RPC server. It calls the MetaWeblog API’s “New Post” method, and passes it some values. The parameters for this method are as follows:
Parameter Description
BlogID not used (yet)
Username the authenticated username that has permission to create posts via XML-RPC
Password the username’s associated password
Content the ARRAY of values that will be converted to XML by our XML-RPC library, and sent to Wordpress. There are a plethora of array key values that Wordpress supports for this data structure, but many of them are Wordpress specific. If you wish to remain more true to the specification, the ones I’ve shown are about all you’ve got.
Publish a boolean value to tell whether or not to immediately publish the post; in this example, it will create a draft entry, requiring someone to check it before publishing.

So we query the Wordpress XML-RPC server to create our new blog post, and if it’s successful, it returns the newly created blog posts’ ID field. The neat thing about this, is that (again, as of Wordpress version 2.7), if you wish to preview a blog post, you can use your Wordpress installation’s URL and adding a short query string to the end with this blog ID. For example, let’s assume this returned the ID of 3, the preview URL would then be:

http://www.example.com/?p=3
Pretty easy, huh? Here’s the full sample code without any breaks:
view sourceprint?
01<?php
02    include("../wp-includes/class-IXR.php");
03    $client = new IXR_Client('http://www.example.com/xmlrpc.php');
04
05    if (!$client->query('wp.getCategories','', 'admin',’password’)) {
06        die('An error occurred - '.$client->getErrorCode().":".$client->getErrorMessage());
07    }
08    $response = $client->getResponse();
09
10    $content['title'] = 'Test Draft Entry using MetaWeblog API';
11    $content['categories'] = array($response[1]['categoryName']);
12    $content['description'] = '<p>Hello World!</p>';
13    if (!$client->query('metaWeblog.newPost','', 'admin',’password’, $content, false)) {
14        die('An error occurred - '.$client->getErrorCode().":".$client->getErrorMessage());
15    }
16    echo $client->getResponse();    //with Wordpress, will report the ID of the new post
17?>
Hopefully having this documented somewhere will help someone out. I’ve used it at the work to allow librarians to upload exported XML New Item Record reports to the server, let it be processed, and then post the processed output to a Wordpress Draft where it can be reviewed for any irregularities or errors, and then posted for our public to see.

 

No comments:

Post a Comment