It was brought to my attention last week that there aren’t very many good tutorials on the web regarding the use of XML-RPC in WordPress. Sure, there are plenty that talk about how easy it is to use and how great of a tool it can be, but few examples explaining just how it can be used.
looks like I’m mostly on my own when it comes to digging deep on XML-RPC in WordPress
— curtismchale
I use WordPress for just about everything. For websites, for forums, for ebook sales, for presentations, and most recently for an SMS gateway to a travel blog. The thing is, I can’t always post to WordPress the way I want to. I will be in Haiti next week and won’t have access to a computer or a laptop, but I still want to update my blog so I can communicate with friends and family at home. XML-RPC to the rescue!
Well, not exactly.
The first part of my application is actually a custom handler for SMS messages that I set up on my server. I won’t get into that part of the system for now; instead, I’ll explain how the system updates a remote blog hosted on WordPress.com using XML-RPC.
The Tools
There is just about no limit to what you can do with WordPress through XML-RPC calls. You can add posts, edit comments, upload images, manage taxonomies, and even configure site options. If there’s something you want to do that’s not exposed through the API, you can add your own calls with a simple filter.
From the receiving end of things, the XML-RPC system in WordPress is fantastic. All of the ugly XML is converted to native PHP objects (and arrays and strings) so you can program along without needing to worry about content structs, unclosed tags, or remembering whether to use
or
to mark a number.
The heavier part of the API is the sending end of things. How do you get your data into that scary-looking content struct? How do you structure your XML so WordPress can read it? How do you interpret errors thrown by the server?
Luckily, these questions are already answered for you.
Most systems support their own XML-RPC library – WordPress is no different. While there is a robust server library available, there is also a robust client library available as well. You can use this library to execute XML-RPC requests from within WordPress to interact with or consume data from any XML-RPC server you like.
The Framework
In the case of my SMS link, I need to pass a “new post” request to WordPress.com. I could simply use an existing service like IFTTT to trigger post creation 1, but their system doesn’t support post formats. I want to keep my regular posts separate from my SMS updates, so I’ll be using the “status” post format for these separate updates.
Creating a post with a specified post format requires a custom call through my own, self-hosted XML-RPC client. Luckily, I’m already using WordPress to host the SMS gateway, so I can use WordPress to push the update to the server as well.
Just include the Incutio XML-RPC library that ships with WordPress to get base functionality and WordPress’ internal HTTP XML-RPC client library to get started. The first is the workhorse that translates native PHP objects and collections back and forth into XML-RPC structures. The second is a beautiful abstraction of the request/response process that makes live so much easier.
1
2 |
include_once( ABSPATH . WPINC . '/class-IXR.php' );
include_once( ABSPATH . WPINC . '/class-wp-http-ixr-client.php' ); |
Walking Through a Request
Every WordPress installation ships with a default XML-RPC endpoint. 2 In most cases, it’s discoverable as well – just check for the
http://yoursite.com/xmlrpc.php
.
We’ll start building our request by creating a new client pointed at that endpoint.
1
|
$client = new WP_HTTP_IXR_CLIENT( 'http://yoursite.com/xmlrpc.php' );
|
Now let’s make a call. For this specific request, we want to call wp.newPost
to create the new post. We’ll pass in an array of arguments that WordPress presents:
- 0 – The blog ID, but it’s not really used.
- ericmann – My WordPress username for the site.
- ….. – My WordPress password 3
- array() – The content structure. An associative array of the fields I want set for the newly created post.
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
$result = $client->query( 'wp.newPost', array(
0, "ericmann", "....", array( 'post_status' => 'publish', 'post_title' => 'SMS Update', 'post_content' => $_REQUEST['text'], 'post_format' => 'status', 'terms_names' => array( 'category' => array( 'Field Update' ), 'post_tag' => array( 'mobile', 'update' ) ) ) ) ); |
Nothing really fancy is happening here. You could think of this as simply invoking wp_insert_post()
on a remote site. Really, that is what you’re doing. When WordPress receives the request, it sanitizes the data (to make sure you aren’t sending garbage), calls wp_insert_post()
, and returns the ID of the newly created post.
Now on the client side, you check to see if the request was successful. If it was, you’ll get true
. If it wasn’t, you’ll get back false
as a result and can check the error
property of your client object to see what all happened.
1
2 3 4 5 6 |
if ( $result ) {
update_post_meta( $new_post_id, 'posted', 'Success' ); } else { $error = $client->error->message; update_post_meta( $new_post_id, 'posted', 'Failed: ' . $error ); } |
If you absolutely need the ID back as well, you can set the debug
flag to true
on the client object and it will record both the method call and the method response.
What’s Next?
Making requests is pretty simple, but if you want to get started and are worried about corrupting your database, WordPress ships with two test methods in its XML-RPC server:
-
demo.sayHello
– Returns a standard “Hello!” message. -
demo.addTwoNumbers
– Accepts an array containing two numbers and returns the sum.
So to get started, you can merely create a request using one of these test messages: 4
1
2 3 4 5 6 7 8 9 |
include_once( ABSPATH . WPINC . '/class-IXR.php' );
include_once( ABSPATH . WPINC . '/class-wp-http-ixr-client.php' ); $client = new WP_HTTP_IXR_CLIENT( 'http://wordpress.com/xmlrpc.php' ); $client->debug = true; $hello = $client->query( 'demo.sayHello' ); $addition = $client->query( 'demo.addTwoNumbers', array( 55, 17 ) ); |
These commands should give you these blocks of XML:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
version="1.0"?>
>> version="1.0" encoding="UTF-8"?> > > > > > version="1.0"?> > >>>> >> version="1.0" encoding="UTF-8"?> > > > > > |
Notes:
- They’re using an XML-RPC client under the surface as well! ↩
- This will be customizable with a filter in an upcoming version of WordPress, but even when filtered the endpoint will still be available somewhere. ↩
- You didn’t really think I’d give you my password, did you? ↩
- Yes, I have tested this exact code. It works just fine. ↩
Great Post. Follow up for the SMS Gateway wanted.
Oh, there will definitely be a followup I have great plans for that platform.
Thanks for sharing it solve my problem.
Good tutorial but something isn’t working right. I tried the last example with the demo.sayHello and demo.addTwoNumbers and this is only output I received:
It looks like the call is formed correctly, do I need certain modules or something installed on my server? Or maybe those two included files changed since October? Thoughts?
Nope, nothing’s changed. I just re-ran the exact code against a fresh install of WordPress 3.5.1 to be doubly sure. Where are you running the code? If you’re running this through a browser, the extra XML might be hidden by default (view-source or inspect element might reveal it).
I’m running this from test.php which I created at the root of the WordPress installation and I’m directly accessing this page by pointing my browser to mydomain.com/test.php. The browser isn’t hiding any xml (but good idea. )
I turned on error reporting and got the following error: Fatal error: Call to undefined function wp_remote_post() in /var/www/vhosts/burnhamrichards.com/httpdocs/wp-includes/class-wp-http-ixr-client.php on line 58
I tried including that file as well and still no luck but a new error: Fatal error: Class ‘WP_Http’ not found in /var/www/vhosts/burnhamrichards.com/httpdocs/wp-includes/http.php on line 26
Here’s the .
You can’t call WP core like that. Start with `wp-load.php`, etc.
Ah, OK, that makes sense. The example code was working under the assumption that you were loading things within an existing WordPress environment (hence the error referencing WP_Http as missing). You’ll either need to in your test file, or bundle your code inside a plugin and run from within WordPress.
That fixed it! Thanks for the help Kaiser & Eric.
What are you doing with update_post_meta()? I mean what is that about? Any further input from you would be appreciated though I will certainly understand if you are too busy to say anything further.
Thanks for posting your code regardless!
Carlos
The code for this example was taken from another project. The $new_post_id variable was the ID of a custom post type entry for an XML_RPC log. So, after you make the remote request, you store whether or not it’s successful in post meta on your log object so you can check it out later.
Really, you could do anything you want inside that conditional – if true, print a success message in the browser, for example. The code I chose to use saved the result to the database.
A project was release here http://letrunghieu.github.io/wordpress-xmlrpc-client/ It has a full testsuite and implement the XML-RPC WordPress API closely.
if you need the RPC return value, such as the user or post id, you can get it by calling
$client->getResponse();
right after the corresponding $client->query(); call.
If you need access to other WP functions, such as create_user for example, there is a handy plugin that gives you access to all WP functions trough the standard WP RPC API:
https://wordpress.org/plugins/extended-xml-rpc-api/
Thank you! This helped me (terms_names)